Recipe Card Section

This commit is contained in:
Kuchenpirat 2025-07-30 09:41:07 +00:00
commit c123e3e2a1

View file

@ -36,11 +36,11 @@
offset-y
start
>
<template #activator="{ props }">
<template #activator="{ props: activatorProps }">
<v-btn
variant="text"
:icon="$vuetify.display.xs"
v-bind="props"
v-bind="activatorProps"
:loading="sortLoading"
>
<v-icon :start="!$vuetify.display.xs">
@ -162,7 +162,7 @@
</div>
</template>
<script lang="ts">
<script setup lang="ts">
import { useThrottleFn } from "@vueuse/core";
import RecipeCard from "./RecipeCard.vue";
import RecipeCardMobile from "./RecipeCardMobile.vue";
@ -175,42 +175,30 @@ import type { RecipeSearchQuery } from "~/lib/api/user/recipes/recipe";
const REPLACE_RECIPES_EVENT = "replaceRecipes";
const APPEND_RECIPES_EVENT = "appendRecipes";
export default defineNuxtComponent({
components: {
RecipeCard,
RecipeCardMobile,
},
props: {
disableToolbar: {
type: Boolean,
default: false,
},
disableSort: {
type: Boolean,
default: false,
},
icon: {
type: String,
default: null,
},
title: {
type: String,
default: null,
},
singleColumn: {
type: Boolean,
default: false,
},
recipes: {
type: Array as () => Recipe[],
default: () => [],
},
query: {
type: Object as () => RecipeSearchQuery,
default: null,
},
},
setup(props, context) {
interface Props {
disableToolbar?: boolean;
disableSort?: boolean;
icon?: string | null;
title?: string | null;
singleColumn?: boolean;
recipes?: Recipe[];
query?: RecipeSearchQuery | null;
}
const props = withDefaults(defineProps<Props>(), {
disableToolbar: false,
disableSort: false,
icon: null,
title: null,
singleColumn: false,
recipes: () => [],
query: null,
});
const emit = defineEmits<{
replaceRecipes: [recipes: Recipe[]];
appendRecipes: [recipes: Recipe[]];
}>();
const { $vuetify } = useNuxtApp();
const preferences = useUserSortPreferences();
@ -234,9 +222,7 @@ export default defineNuxtComponent({
return props.icon || $globals.icons.tags;
});
const state = reactive({
sortLoading: false,
});
const sortLoading = ref(false);
const route = useRoute();
const groupSlug = computed(() => route.params.groupSlug as string || $auth.user.value?.groupSlug || "");
@ -251,7 +237,7 @@ export default defineNuxtComponent({
const router = useRouter();
const queryFilter = computed(() => {
return props.query.queryFilter || null;
return props.query?.queryFilter || null;
// TODO: allow user to filter out null values when ordering by a value that may be null (such as lastMade)
@ -290,7 +276,7 @@ export default defineNuxtComponent({
let lastQuery: string | undefined = JSON.stringify(props.query);
watch(
() => props.query,
async (newValue: RecipeSearchQuery | undefined) => {
async (newValue: RecipeSearchQuery | undefined | null) => {
const newValueString = JSON.stringify(newValue);
if (lastQuery !== newValueString) {
lastQuery = newValueString;
@ -315,7 +301,7 @@ export default defineNuxtComponent({
// since we doubled the first call, we also need to advance the page
page.value = page.value + 1;
context.emit(REPLACE_RECIPES_EVENT, newRecipes);
emit(REPLACE_RECIPES_EVENT, newRecipes);
}
const infiniteScroll = useThrottleFn(async () => {
@ -331,14 +317,14 @@ export default defineNuxtComponent({
hasMore.value = false;
}
if (newRecipes.length) {
context.emit(APPEND_RECIPES_EVENT, newRecipes);
emit(APPEND_RECIPES_EVENT, newRecipes);
}
loading.value = false;
}, 500);
async function sortRecipes(sortType: string) {
if (state.sortLoading || loading.value) {
if (sortLoading.value || loading.value) {
return;
}
@ -403,14 +389,14 @@ export default defineNuxtComponent({
page.value = 1;
hasMore.value = true;
state.sortLoading = true;
sortLoading.value = true;
loading.value = true;
// fetch new recipes
const newRecipes = await fetchRecipes();
context.emit(REPLACE_RECIPES_EVENT, newRecipes);
emit(REPLACE_RECIPES_EVENT, newRecipes);
state.sortLoading = false;
sortLoading.value = false;
loading.value = false;
}
@ -426,22 +412,6 @@ export default defineNuxtComponent({
function toggleMobileCards() {
preferences.value.useMobileCards = !preferences.value.useMobileCards;
}
return {
...toRefs(state),
displayTitleIcon,
EVENTS,
infiniteScroll,
ready,
loading,
navigateRandom,
preferences,
sortRecipes,
toggleMobileCards,
useMobileCards,
};
},
});
</script>
<style>