mirror of
				https://github.com/mealie-recipes/mealie.git
				synced 2025-10-30 09:43:43 -04:00 
			
		
		
		
	feat: implement local storage for sorting and dynamic sort icons on the new recipe sort card (#1506)
* added new sort icons * added dynamic sort icons * implemented local storage for sorting and mobile card view * fixed bug with local storage booleans * added type hints * bum vue use to use merge defaults * use reactive localstorage * add $vuetify type * sort returns * fix type error Co-authored-by: Hayden <64056131+hay-kot@users.noreply.github.com>
This commit is contained in:
		| @@ -61,7 +61,7 @@ | |||||||
|         <template #activator="{ on, attrs }"> |         <template #activator="{ on, attrs }"> | ||||||
|           <v-btn text :icon="$vuetify.breakpoint.xsOnly" v-bind="attrs" :loading="sortLoading" v-on="on"> |           <v-btn text :icon="$vuetify.breakpoint.xsOnly" v-bind="attrs" :loading="sortLoading" v-on="on"> | ||||||
|             <v-icon :left="!$vuetify.breakpoint.xsOnly"> |             <v-icon :left="!$vuetify.breakpoint.xsOnly"> | ||||||
|               {{ $globals.icons.sort }} |               {{ preferences.sortIcon }} | ||||||
|             </v-icon> |             </v-icon> | ||||||
|             {{ $vuetify.breakpoint.xsOnly ? null : $t("general.sort") }} |             {{ $vuetify.breakpoint.xsOnly ? null : $t("general.sort") }} | ||||||
|           </v-btn> |           </v-btn> | ||||||
| @@ -102,11 +102,11 @@ | |||||||
|             event: 'toggle-dense-view', |             event: 'toggle-dense-view', | ||||||
|           }, |           }, | ||||||
|         ]" |         ]" | ||||||
|         @toggle-dense-view="mobileCards = !mobileCards" |         @toggle-dense-view="toggleMobileCards()" | ||||||
|       /> |       /> | ||||||
|     </v-app-bar> |     </v-app-bar> | ||||||
|     <div v-if="recipes" class="mt-2"> |     <div v-if="recipes" class="mt-2"> | ||||||
|       <v-row v-if="!viewScale"> |       <v-row v-if="!useMobileCards"> | ||||||
|         <v-col v-for="(recipe, index) in recipes" :key="recipe.slug + index" :sm="6" :md="6" :lg="4" :xl="3"> |         <v-col v-for="(recipe, index) in recipes" :key="recipe.slug + index" :sm="6" :md="6" :lg="4" :xl="3"> | ||||||
|           <v-lazy> |           <v-lazy> | ||||||
|             <RecipeCard |             <RecipeCard | ||||||
| @@ -174,6 +174,7 @@ import RecipeCardMobile from "./RecipeCardMobile.vue"; | |||||||
| import { useAsyncKey } from "~/composables/use-utils"; | import { useAsyncKey } from "~/composables/use-utils"; | ||||||
| import { useLazyRecipes, useSorter } from "~/composables/recipes"; | import { useLazyRecipes, useSorter } from "~/composables/recipes"; | ||||||
| import { Recipe } from "~/types/api-types/recipe"; | import { Recipe } from "~/types/api-types/recipe"; | ||||||
|  | import { useUserSortPreferences } from "~/composables/use-users/preferences"; | ||||||
|  |  | ||||||
| const SORT_EVENT = "sort"; | const SORT_EVENT = "sort"; | ||||||
| const REPLACE_RECIPES_EVENT = "replaceRecipes"; | const REPLACE_RECIPES_EVENT = "replaceRecipes"; | ||||||
| @@ -211,7 +212,8 @@ export default defineComponent({ | |||||||
|     }, |     }, | ||||||
|   }, |   }, | ||||||
|   setup(props, context) { |   setup(props, context) { | ||||||
|     const mobileCards = ref(false); |     const preferences = useUserSortPreferences(); | ||||||
|  |  | ||||||
|     const utils = useSorter(); |     const utils = useSorter(); | ||||||
|  |  | ||||||
|     const EVENTS = { |     const EVENTS = { | ||||||
| @@ -223,8 +225,8 @@ export default defineComponent({ | |||||||
|     }; |     }; | ||||||
|  |  | ||||||
|     const { $globals, $vuetify } = useContext(); |     const { $globals, $vuetify } = useContext(); | ||||||
|     const viewScale = computed(() => { |     const useMobileCards = computed(() => { | ||||||
|       return mobileCards.value || $vuetify.breakpoint.smAndDown; |       return $vuetify.breakpoint.smAndDown || preferences.value.useMobileCards; | ||||||
|     }); |     }); | ||||||
|  |  | ||||||
|     const displayTitleIcon = computed(() => { |     const displayTitleIcon = computed(() => { | ||||||
| @@ -247,18 +249,20 @@ export default defineComponent({ | |||||||
|  |  | ||||||
|     const page = ref(1); |     const page = ref(1); | ||||||
|     const perPage = ref(30); |     const perPage = ref(30); | ||||||
|     const orderBy = ref("name"); |  | ||||||
|     const orderDirection = ref("asc"); |  | ||||||
|     const hasMore = ref(true); |     const hasMore = ref(true); | ||||||
|  |  | ||||||
|     const ready = ref(false); |     const ready = ref(false); | ||||||
|     const loading = ref(false); |     const loading = ref(false); | ||||||
|  |  | ||||||
|     const { recipes, fetchMore } = useLazyRecipes(); |     const { fetchMore } = useLazyRecipes(); | ||||||
|  |  | ||||||
|     onMounted(async () => { |     onMounted(async () => { | ||||||
|       if (props.usePagination) { |       if (props.usePagination) { | ||||||
|         const newRecipes = await fetchMore(page.value, perPage.value, orderBy.value, orderDirection.value); |         const newRecipes = await fetchMore( | ||||||
|  |           page.value, | ||||||
|  |           perPage.value, | ||||||
|  |           preferences.value.orderBy, | ||||||
|  |           preferences.value.orderDirection | ||||||
|  |         ); | ||||||
|         context.emit(REPLACE_RECIPES_EVENT, newRecipes); |         context.emit(REPLACE_RECIPES_EVENT, newRecipes); | ||||||
|         ready.value = true; |         ready.value = true; | ||||||
|       } |       } | ||||||
| @@ -273,7 +277,12 @@ export default defineComponent({ | |||||||
|         loading.value = true; |         loading.value = true; | ||||||
|         page.value = page.value + 1; |         page.value = page.value + 1; | ||||||
|  |  | ||||||
|         const newRecipes = await fetchMore(page.value, perPage.value, orderBy.value, orderDirection.value); |         const newRecipes = await fetchMore( | ||||||
|  |           page.value, | ||||||
|  |           perPage.value, | ||||||
|  |           preferences.value.orderBy, | ||||||
|  |           preferences.value.orderDirection | ||||||
|  |         ); | ||||||
|         if (!newRecipes.length) { |         if (!newRecipes.length) { | ||||||
|           hasMore.value = false; |           hasMore.value = false; | ||||||
|         } else { |         } else { | ||||||
| @@ -284,51 +293,39 @@ export default defineComponent({ | |||||||
|       }, useAsyncKey()); |       }, useAsyncKey()); | ||||||
|     }, 500); |     }, 500); | ||||||
|  |  | ||||||
|     /* |     /** | ||||||
|     sortRecipes helps filter using the API. This will eventually replace the sortRecipesFrontend function which pulls all recipes |      * sortRecipes helps filter using the API. This will eventually replace the sortRecipesFrontend function which pulls all recipes | ||||||
|     (without pagination) and does the sorting in the frontend. |      * (without pagination) and does the sorting in the frontend. | ||||||
|  |      * TODO: remove sortRecipesFrontend and remove duplicate "sortRecipes" section in the template (above) | ||||||
|     TODO: remove sortRecipesFrontend and remove duplicate "sortRecipes" section in the template (above) |      * @param sortType | ||||||
|     TODO: use indicator to show asc / desc order |  | ||||||
|      */ |      */ | ||||||
|  |  | ||||||
|     function sortRecipes(sortType: string) { |     function sortRecipes(sortType: string) { | ||||||
|       if (state.sortLoading || loading.value) { |       if (state.sortLoading || loading.value) { | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       function setter(orderBy: string, ascIcon: string, descIcon: string) { | ||||||
|  |         if (preferences.value.orderBy !== orderBy) { | ||||||
|  |           preferences.value.orderBy = orderBy; | ||||||
|  |           preferences.value.orderDirection = "asc"; | ||||||
|  |         } else { | ||||||
|  |           preferences.value.orderDirection = preferences.value.orderDirection === "asc" ? "desc" : "asc"; | ||||||
|  |         } | ||||||
|  |         preferences.value.sortIcon = preferences.value.orderDirection === "asc" ? ascIcon : descIcon; | ||||||
|  |       } | ||||||
|  |  | ||||||
|       switch (sortType) { |       switch (sortType) { | ||||||
|         case EVENTS.az: |         case EVENTS.az: | ||||||
|           if (orderBy.value !== "name") { |           setter("name", $globals.icons.sortAlphabeticalAscending, $globals.icons.sortAlphabeticalDescending); | ||||||
|             orderBy.value = "name"; |  | ||||||
|             orderDirection.value = "asc"; |  | ||||||
|           } else { |  | ||||||
|             orderDirection.value = orderDirection.value === "asc" ? "desc" : "asc"; |  | ||||||
|           } |  | ||||||
|           break; |           break; | ||||||
|         case EVENTS.rating: |         case EVENTS.rating: | ||||||
|           if (orderBy.value !== "rating") { |           setter("rating", $globals.icons.sortAscending, $globals.icons.sortDescending); | ||||||
|             orderBy.value = "rating"; |  | ||||||
|             orderDirection.value = "desc"; |  | ||||||
|           } else { |  | ||||||
|             orderDirection.value = orderDirection.value === "asc" ? "desc" : "asc"; |  | ||||||
|           } |  | ||||||
|           break; |           break; | ||||||
|         case EVENTS.created: |         case EVENTS.created: | ||||||
|           if (orderBy.value !== "created_at") { |           setter("created_at", $globals.icons.sortCalendarAscending, $globals.icons.sortCalendarDescending); | ||||||
|             orderBy.value = "created_at"; |  | ||||||
|             orderDirection.value = "desc"; |  | ||||||
|           } else { |  | ||||||
|             orderDirection.value = orderDirection.value === "asc" ? "desc" : "asc"; |  | ||||||
|           } |  | ||||||
|           break; |           break; | ||||||
|         case EVENTS.updated: |         case EVENTS.updated: | ||||||
|           if (orderBy.value !== "update_at") { |           setter("updated_at", $globals.icons.sortClockAscending, $globals.icons.sortClockDescending); | ||||||
|             orderBy.value = "update_at"; |  | ||||||
|             orderDirection.value = "desc"; |  | ||||||
|           } else { |  | ||||||
|             orderDirection.value = orderDirection.value === "asc" ? "desc" : "asc"; |  | ||||||
|           } |  | ||||||
|           break; |           break; | ||||||
|         default: |         default: | ||||||
|           console.log("Unknown Event", sortType); |           console.log("Unknown Event", sortType); | ||||||
| @@ -344,7 +341,12 @@ export default defineComponent({ | |||||||
|         loading.value = true; |         loading.value = true; | ||||||
|  |  | ||||||
|         // fetch new recipes |         // fetch new recipes | ||||||
|         const newRecipes = await fetchMore(page.value, perPage.value, orderBy.value, orderDirection.value); |         const newRecipes = await fetchMore( | ||||||
|  |           page.value, | ||||||
|  |           perPage.value, | ||||||
|  |           preferences.value.orderBy, | ||||||
|  |           preferences.value.orderDirection | ||||||
|  |         ); | ||||||
|         context.emit(REPLACE_RECIPES_EVENT, newRecipes); |         context.emit(REPLACE_RECIPES_EVENT, newRecipes); | ||||||
|  |  | ||||||
|         state.sortLoading = false; |         state.sortLoading = false; | ||||||
| @@ -379,17 +381,22 @@ export default defineComponent({ | |||||||
|       state.sortLoading = false; |       state.sortLoading = false; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     function toggleMobileCards() { | ||||||
|  |       preferences.value.useMobileCards = !preferences.value.useMobileCards; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return { |     return { | ||||||
|       mobileCards, |  | ||||||
|       ...toRefs(state), |       ...toRefs(state), | ||||||
|       EVENTS, |  | ||||||
|       viewScale, |  | ||||||
|       displayTitleIcon, |       displayTitleIcon, | ||||||
|  |       EVENTS, | ||||||
|       infiniteScroll, |       infiniteScroll, | ||||||
|       loading, |       loading, | ||||||
|       navigateRandom, |       navigateRandom, | ||||||
|  |       preferences, | ||||||
|       sortRecipes, |       sortRecipes, | ||||||
|       sortRecipesFrontend, |       sortRecipesFrontend, | ||||||
|  |       toggleMobileCards, | ||||||
|  |       useMobileCards, | ||||||
|     }; |     }; | ||||||
|   }, |   }, | ||||||
| }); | }); | ||||||
|   | |||||||
							
								
								
									
										28
									
								
								frontend/composables/use-users/preferences.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								frontend/composables/use-users/preferences.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | import { Ref, useContext } from "@nuxtjs/composition-api"; | ||||||
|  | import { useLocalStorage } from "@vueuse/core"; | ||||||
|  |  | ||||||
|  | export interface UserRecipePreferences { | ||||||
|  |   orderBy: string; | ||||||
|  |   orderDirection: string; | ||||||
|  |   sortIcon: string; | ||||||
|  |   useMobileCards: boolean; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | export function useUserSortPreferences(): Ref<UserRecipePreferences> { | ||||||
|  |   const { $globals } = useContext(); | ||||||
|  |  | ||||||
|  |   const fromStorage = useLocalStorage( | ||||||
|  |     "recipe-section-preferences", | ||||||
|  |     { | ||||||
|  |       orderBy: "name", | ||||||
|  |       orderDirection: "asc", | ||||||
|  |       sortIcon: $globals.icons.sortAlphabeticalAscending, | ||||||
|  |       useMobileCards: false, | ||||||
|  |     }, | ||||||
|  |     { mergeDefaults: true } | ||||||
|  |     // we cast to a Ref because by default it will return an optional type ref | ||||||
|  |     // but since we pass defaults we know all properties are set. | ||||||
|  |   ) as Ref<UserRecipePreferences>; | ||||||
|  |  | ||||||
|  |   return fromStorage; | ||||||
|  | } | ||||||
| @@ -22,7 +22,7 @@ | |||||||
|     "@nuxtjs/proxy": "^2.1.0", |     "@nuxtjs/proxy": "^2.1.0", | ||||||
|     "@nuxtjs/pwa": "^3.3.5", |     "@nuxtjs/pwa": "^3.3.5", | ||||||
|     "@vue/composition-api": "^1.6.2", |     "@vue/composition-api": "^1.6.2", | ||||||
|     "@vueuse/core": "^8.5.0", |     "@vueuse/core": "^9.0.2", | ||||||
|     "core-js": "^3.23.1", |     "core-js": "^3.23.1", | ||||||
|     "date-fns": "^2.28.0", |     "date-fns": "^2.28.0", | ||||||
|     "fuse.js": "^6.6.2", |     "fuse.js": "^6.6.2", | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| import { Plugin } from "@nuxt/types" | import { Plugin } from "@nuxt/types"; | ||||||
|  | import { Framework } from "vuetify"; | ||||||
| import { icons } from "~/utils/icons"; | import { icons } from "~/utils/icons"; | ||||||
| import { Icon } from "~/utils/icons/icon-type"; | import { Icon } from "~/utils/icons/icon-type"; | ||||||
|  |  | ||||||
| @@ -15,13 +16,14 @@ declare module "vue/types/vue" { | |||||||
| declare module "@nuxt/types" { | declare module "@nuxt/types" { | ||||||
|   interface Context { |   interface Context { | ||||||
|     $globals: Globals; |     $globals: Globals; | ||||||
|  |     $vuetify: Framework; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| const globalsPlugin: Plugin = (_, inject) => { | const globalsPlugin: Plugin = (_, inject) => { | ||||||
|   inject("globals", { |   inject("globals", { | ||||||
|     icons |     icons, | ||||||
|   }); |   }); | ||||||
| }; | }; | ||||||
|  |  | ||||||
| export default globalsPlugin | export default globalsPlugin; | ||||||
|   | |||||||
| @@ -78,6 +78,14 @@ export interface Icon { | |||||||
|   shareVariant: string; |   shareVariant: string; | ||||||
|   shuffleVariant: string; |   shuffleVariant: string; | ||||||
|   sort: string; |   sort: string; | ||||||
|  |   sortAscending: string; | ||||||
|  |   sortDescending: string; | ||||||
|  |   sortAlphabeticalAscending: string; | ||||||
|  |   sortAlphabeticalDescending: string; | ||||||
|  |   sortCalendarAscending: string; | ||||||
|  |   sortCalendarDescending: string; | ||||||
|  |   sortClockAscending: string; | ||||||
|  |   sortClockDescending: string; | ||||||
|   star: string; |   star: string; | ||||||
|   testTube: string; |   testTube: string; | ||||||
|   tools: string; |   tools: string; | ||||||
|   | |||||||
| @@ -45,6 +45,14 @@ import { | |||||||
|   mdiCodeJson, |   mdiCodeJson, | ||||||
|   mdiCog, |   mdiCog, | ||||||
|   mdiSort, |   mdiSort, | ||||||
|  |   mdiSortAscending, | ||||||
|  |   mdiSortDescending, | ||||||
|  |   mdiSortAlphabeticalAscending, | ||||||
|  |   mdiSortAlphabeticalDescending, | ||||||
|  |   mdiSortCalendarAscending, | ||||||
|  |   mdiSortCalendarDescending, | ||||||
|  |   mdiSortClockAscending, | ||||||
|  |   mdiSortClockDescending, | ||||||
|   mdiOrderAlphabeticalAscending, |   mdiOrderAlphabeticalAscending, | ||||||
|   mdiStar, |   mdiStar, | ||||||
|   mdiNewBox, |   mdiNewBox, | ||||||
| @@ -194,6 +202,14 @@ export const icons = { | |||||||
|   shareVariant: mdiShareVariant, |   shareVariant: mdiShareVariant, | ||||||
|   shuffleVariant: mdiShuffleVariant, |   shuffleVariant: mdiShuffleVariant, | ||||||
|   sort: mdiSort, |   sort: mdiSort, | ||||||
|  |   sortAscending: mdiSortAscending, | ||||||
|  |   sortDescending: mdiSortDescending, | ||||||
|  |   sortAlphabeticalAscending: mdiSortAlphabeticalAscending, | ||||||
|  |   sortAlphabeticalDescending: mdiSortAlphabeticalDescending, | ||||||
|  |   sortCalendarAscending: mdiSortCalendarAscending, | ||||||
|  |   sortCalendarDescending: mdiSortCalendarDescending, | ||||||
|  |   sortClockAscending: mdiSortClockAscending, | ||||||
|  |   sortClockDescending: mdiSortClockDescending, | ||||||
|   star: mdiStar, |   star: mdiStar, | ||||||
|   testTube: mdiTestTube, |   testTube: mdiTestTube, | ||||||
|   tools: mdiTools, |   tools: mdiTools, | ||||||
|   | |||||||
| @@ -2227,6 +2227,11 @@ | |||||||
|   dependencies: |   dependencies: | ||||||
|     source-map "^0.6.1" |     source-map "^0.6.1" | ||||||
|  |  | ||||||
|  | "@types/web-bluetooth@^0.0.15": | ||||||
|  |   version "0.0.15" | ||||||
|  |   resolved "https://registry.yarnpkg.com/@types/web-bluetooth/-/web-bluetooth-0.0.15.tgz#d60330046a6ed8a13b4a53df3813c44942ebdf72" | ||||||
|  |   integrity sha512-w7hEHXnPMEZ+4nGKl/KDRVpxkwYxYExuHOYXyzIzCDzEZ9ZCGMAewulr9IqJu2LR4N37fcnb1XVeuZ09qgOxhA== | ||||||
|  |  | ||||||
| "@types/webpack-bundle-analyzer@3.9.3": | "@types/webpack-bundle-analyzer@3.9.3": | ||||||
|   version "3.9.3" |   version "3.9.3" | ||||||
|   resolved "https://registry.yarnpkg.com/@types/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.3.tgz#3a12025eb5d86069c30b47a157e62c0aca6e39a1" |   resolved "https://registry.yarnpkg.com/@types/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.9.3.tgz#3a12025eb5d86069c30b47a157e62c0aca6e39a1" | ||||||
| @@ -2550,24 +2555,25 @@ | |||||||
|   resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.37.tgz#8e6adc3f2759af52f0e85863dfb0b711ecc5c702" |   resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.37.tgz#8e6adc3f2759af52f0e85863dfb0b711ecc5c702" | ||||||
|   integrity sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw== |   integrity sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw== | ||||||
|  |  | ||||||
| "@vueuse/core@^8.5.0": | "@vueuse/core@^9.0.2": | ||||||
|   version "8.5.0" |   version "9.0.2" | ||||||
|   resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-8.5.0.tgz#2b7548e52165c88e1463756c36188e105d806543" |   resolved "https://registry.yarnpkg.com/@vueuse/core/-/core-9.0.2.tgz#e6e59c45b43c1ffe4ad5149853a1ea4e8f1e3b12" | ||||||
|   integrity sha512-VEJ6sGNsPlUp0o9BGda2YISvDZbhWJSOJu5zlp2TufRGVrLcYUKr31jyFEOj6RXzG3k/H4aCYeZyjpItfU8glw== |   integrity sha512-kOIqaQPSs7OSByWg1ulEKRUJbsq3FmbJiUr0RhEKpt3O1Uhl4DrDj85DUbQBABVYgPvSaY6AE/fP3/FOcRIOoQ== | ||||||
|   dependencies: |   dependencies: | ||||||
|     "@vueuse/metadata" "8.5.0" |     "@types/web-bluetooth" "^0.0.15" | ||||||
|     "@vueuse/shared" "8.5.0" |     "@vueuse/metadata" "9.0.2" | ||||||
|  |     "@vueuse/shared" "9.0.2" | ||||||
|     vue-demi "*" |     vue-demi "*" | ||||||
|  |  | ||||||
| "@vueuse/metadata@8.5.0": | "@vueuse/metadata@9.0.2": | ||||||
|   version "8.5.0" |   version "9.0.2" | ||||||
|   resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-8.5.0.tgz#1aaa3787922cfda0f38243aaa7779366a669b4db" |   resolved "https://registry.yarnpkg.com/@vueuse/metadata/-/metadata-9.0.2.tgz#373fdeb552f2a002ddc1f36c4027c936d78f8cb5" | ||||||
|   integrity sha512-WxsD+Cd+bn+HcjpY6Dl9FJ8ywTRTT9pTwk3bCQpzEhXVYAyNczKDSahk50fCfIJKeWHhyI4B2+/ZEOxQAkUr0g== |   integrity sha512-TRh+TNUYXiodatSAxd0xZc7sh4RfktVVgNFIN7TCQXKyancbCAcWfHvKfgdlX8LcqSBxKoHVa90n0XdUbboTkw== | ||||||
|  |  | ||||||
| "@vueuse/shared@8.5.0": | "@vueuse/shared@9.0.2": | ||||||
|   version "8.5.0" |   version "9.0.2" | ||||||
|   resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-8.5.0.tgz#fa01ecd3161933f521dd6428b9ef8015ded1bbd3" |   resolved "https://registry.yarnpkg.com/@vueuse/shared/-/shared-9.0.2.tgz#d3fb03594a9482d264702c67efe71d691ce67084" | ||||||
|   integrity sha512-qKG+SZb44VvGD4dU5cQ63z4JE2Yk39hQUecR0a9sEdJA01cx+XrxAvFKJfPooxwoiqalAVw/ktWK6xbyc/jS3g== |   integrity sha512-KwBDefK2ljLESpt0ffe2w8EGUCb3IaMfTzeytB/uHHjHOGOEIHLHHyn8W2C48uGQEvoe5iwaW4Bfp8cRUM6IFA== | ||||||
|   dependencies: |   dependencies: | ||||||
|     vue-demi "*" |     vue-demi "*" | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user