Skip to content

Commit

Permalink
Add infinite scrolling (#10)
Browse files Browse the repository at this point in the history
* feat: add infinite scrolling

* chore: ignore json callback data in code coverage
  • Loading branch information
IronSinew authored Mar 26, 2024
1 parent a30edac commit dad5cc6
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 77 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ docker-compose up -d php
### Other
- [ ] Customizable intro blurb and logo
- [x] Recent recipes on homepage
- [ ] Infinite scroll for recipe lists
- [x] Infinite scroll for recipe lists
### Possible future features
- [ ] "I made it" counter
- [ ] Reviews/ratings
Expand Down
14 changes: 11 additions & 3 deletions app/Http/Controllers/CategoryController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,17 @@ public function index(Request $request)

public function show(Category $category, Request $request)
{
return Inertia::render('Category/CategoryShow')->with([
'category' => fn () => $category,
'recipes' => fn () => $category->recipes,
$perPageAmount = 9;

//@codeCoverageIgnoreStart
if ($request->wantsJson()) {
return $category->recipes()->orderBy('id')->cursorPaginate($perPageAmount);
}
//@codeCoverageIgnoreEnd

return Inertia::render('Recipe/RecipeList')->with([
'label' => fn () => $category,
'recipes' => fn () => $category->recipes()->orderBy('id')->cursorPaginate($perPageAmount),
]);
}
}
12 changes: 10 additions & 2 deletions app/Http/Controllers/LabelController.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,17 @@ public function index(Request $request)

public function show(Label $label, Request $request)
{
return Inertia::render('Label/LabelShow')->with([
$perPageAmount = 9;

//@codeCoverageIgnoreStart
if ($request->wantsJson()) {
return $label->recipes()->orderBy('id')->cursorPaginate($perPageAmount);
}
//@codeCoverageIgnoreEnd

return Inertia::render('Recipe/RecipeList')->with([
'label' => fn () => $label,
'recipes' => fn () => $label->recipes,
'recipes' => fn () => $label->recipes()->orderBy('id')->cursorPaginate($perPageAmount),
]);
}
}
Binary file modified bun.lockb
Binary file not shown.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
"vue": "^3.3.13"
},
"dependencies": {
"@vueuse/components": "^10.9.0",
"@vueuse/core": "^10.9.0",
"marked": "^12.0.1",
"pluralize": "^8.0.0",
"primeicons": "^6.0.1",
Expand Down
34 changes: 0 additions & 34 deletions resources/js/Pages/Category/CategoryShow.vue

This file was deleted.

34 changes: 0 additions & 34 deletions resources/js/Pages/Label/LabelShow.vue

This file was deleted.

99 changes: 99 additions & 0 deletions resources/js/Pages/Recipe/RecipeList.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
<script setup>
import AppLayout from '@/Layouts/AppLayout.vue';
import RecipeCard from "@/Components/RecipeCard.vue";
import {onMounted, ref, watch} from "vue";
import { useIntersectionObserver } from '@vueuse/core'
const props = defineProps({
label: {
type: [Array, Object],
required: false,
default() {
return {};
},
},
recipes: {
type: [Array, Object],
required: false,
default() {
return [];
},
},
});
watch(() => props.recipes, (data, prevData) => {
paginationLink.value = data.recipes.next_cursor;
recipeList.value = data.recipes;
});
const paginationLink = ref(null);
const recipeList = ref([]);
const last = ref(null);
const noMoreScrolling = ref(false);
const isLoading = ref(false);
onMounted(() => {
paginationLink.value = props.recipes.next_page_url;
})
useIntersectionObserver(last, ([{ isIntersecting }]) => {
if (! isIntersecting) {
return;
}
onLoadMore();
})
const onLoadMore = () => {
if (noMoreScrolling.value) {
return;
}
isLoading.value = true;
axios.get(paginationLink.value).then((req) => {
if (req.data.next_page_url === null) {
noMoreScrolling.value = true;
}
recipeList.value = [...recipeList.value, ...req.data.data];
paginationLink.value = req.data.next_page_url;
}).finally(() => {
isLoading.value = false;
});
}
</script>

<template>
<AppLayout :title="`${label.name} label`">
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<h1 class="text-5xl text-surface-0 mb-10">{{ label.name }}</h1>
<div class="grid sm:grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-10">
<transition-group name="fade">
<RecipeCard v-for="recipe in recipeList" :key="recipe.slug" :recipe="recipe"></RecipeCard>
</transition-group>
<RecipeCard v-if="isLoading" v-for="skeleton in 9" :skeleton="true"></RecipeCard>
</div>
<div ref="last" class="py-7"></div>
</div>
</div>
</AppLayout>
</template>

<style lang="scss" scoped>
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.fade-enter-to,
.fade-leave-from {
opacity: 1;
}
.fade-enter-active,
.fade-leave-active {
transition: opacity 1s ease;
}
</style>

4 changes: 2 additions & 2 deletions tests/Feature/Http/Controllers/CategoryControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,8 @@ public function show_displays_view(): void

$response->assertOk();
$response->assertInertia(fn (Assert $page) => $page
->component('Category/CategoryShow')
->where('category.name', $randomCategory->name)
->component('Recipe/RecipeList')
->where('label.name', $randomCategory->name)
);
}
}
2 changes: 1 addition & 1 deletion tests/Feature/Http/Controllers/LabelControllerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function show_displays_view(): void

$response->assertOk();
$response->assertInertia(fn (Assert $page) => $page
->component('Label/LabelShow')
->component('Recipe/RecipeList')
->where('label.name', $randomLabel->name)
);
}
Expand Down

0 comments on commit dad5cc6

Please sign in to comment.