-
-
Notifications
You must be signed in to change notification settings - Fork 48
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Pagination #103
Comments
With the API above, behind the scenes in {
"path": "/blog/3",
"pager": 3,
"type": "blog",
"filename": "blog-post-3.json",
"fields": {
"title": "Post 3",
"body": "Lorem ipsum..",
"author": "Jim Fisk",
"date": "12/24/2020"
}
} Then in the Svelte templates you would just initialize your <script>
export let content, allContent; // these are magic helper variables from Plenti.
let currentPage = content.pager; // get the new "pager" key from the content source.
let postsPerPage = 10;
let allPosts = allContent.filter(content => content.type == "blog");
let totalPosts = allPosts.length;
let totalPages = Math.ceil(totalPosts / postsPerPage);
$: postRangeHigh = currentPage * postsPerPage;
$: postRangeLow = postRangeHigh - postsPerPage;
const setCurrentPage = newPage => {
currentPage = newPage;
}
</script>
{#each allPosts as post, i}
{#if i >= postRangeLow && i < postRangeHigh}
<h3>{post.title}</h3>
<div>{post.body}</div>
{/if}
{/each}
<ul>
{#if currentPage > 1}
<li><a href="/blog" on:click={() => setCurrentPage(1)}>first</a></li>
<li><a href="/blog/{currentPage - 1}" on:click={() => setCurrentPage(currentPage - 1)}>previous</a></li>
{/if}
{#each [3,2,1] as i}
{#if currentPage - i > 0}
<li><a href="/blog/{currentPage - i}" on:click={() => setCurrentPage(currentPage - i)}>{currentPage - i}</a></li>
{/if}
{/each}
<li><span>{currentPage}</span></li>
{#each Array(3) as _, i}
{#if currentPage + (i+1) <= totalPages}
<li><a href="/blog/{currentPage + (i+1)}" on:click={() => setCurrentPage(currentPage + (i+1))}>{currentPage + (i+1)}</a></li>
{/if}
{/each}
{#if currentPage < totalPages}
<li><a href="/blog/{currentPage + 1}" on:click={() => setCurrentPage(currentPage + 1)}>next</a></li>
<li><a href="/blog/{totalPages}" on:click={() => setCurrentPage(totalPages)}>last</li>
{/if}
</ul> Here's a Svelte REPL to show what this looks like in action: https://svelte.dev/repl/877286c4f73e419fba262538a727a5ad?version=3.31.0 (I had to use |
I would like to simplify the route override api to simply reference the variable name from the svelte template that holds the value for the total number of pages instead of recalculating it. That way we're not duplicating this logic in the {
"types": {
"blog": "/blog/:paginate(totalPages)"
}
} |
I wonder if we also need to account for multiple pagers on the same page? I don't think it's a common use case but I see a scenario where someone might want this. For example, if you had two tables of information on the same page, you could be on the 2nd paged output for one, and the 5th for the other. Let's pretend we have a "cats" content type and a "dogs" content type each with 100 content files. If we had an "animals" page with a cats table that displays 10 entries at a time and a dogs table that does the same, we would probably want server fallbacks for each combination (10^2 or 100 unique pages for the "animals" landing page). The route override in {
"types": {
"blog": "/animals/cats/:paginate(totalCats)/dogs/:paginate(totalDogs)"
}
} Which would produce URLs that could look like We would have to update the |
I'm thinking the paginated output can be omitted from |
SSR Output after making global varvar plenti_global_pager_totalPages;
/* generated by Svelte v3.29.4 */
/*import { create_ssr_component, each, escape } from "svelte/internal";*/
let postsPerPage = 2;
var layout_content_pager_svelte = create_ssr_component(($$result, $$props, $$bindings, slots) => {
let allContent = ["hi", "bye", "lie", "tie", "fry", "cry", "pie", "my", "guy"];
let currentPage = 3; // Update this to simulate page change.
let allPosts = allContent;
let totalPosts = allPosts.length;
let totalPages = Math.ceil(totalPosts / postsPerPage);
plenti_global_pager_totalPages = totalPages;
const setCurrentPage = newPage => {
currentPage = newPage;
};
let postRangeHigh;
let postRangeLow;
postRangeHigh = currentPage * postsPerPage;
postRangeLow = postRangeHigh - postsPerPage;
return `${each(allPosts, (post, i) => `${i >= postRangeLow && i < postRangeHigh
? `<h3>${escape(post)}</h3>`
: ``}`)}
<ul>${currentPage > 1
? `<li><a href="${"/blog"}">first</a></li>
<li><a href="${"/blog/" + escape(currentPage - 1)}">previous</a></li>`
: ``}
${each([3, 2, 1], i => `${currentPage - i > 0
? `<li><a href="${"/blog/" + escape(currentPage - i)}">${escape(currentPage - i)}</a></li>`
: ``}`)}
<li><span>${escape(currentPage)}</span></li>
${each(Array(3), (_, i) => `${currentPage + (i + 1) <= totalPages
? `<li><a href="${"/blog/" + escape(currentPage + (i + 1))}">${escape(currentPage + (i + 1))}</a></li>`
: ``}`)}
${currentPage < totalPages
? `<li><a href="${"/blog/" + escape(currentPage + 1)}">next</a></li>
<li><a href="${"/blog/" + escape(totalPages)}">last</a></li>`
: ``}</ul>`;
});
/*export default Component;*/ |
Here's a working example of pagination with static fallbacks in plenti: https://github.com/jimafisk/plenti_pager_example. It's better to work from this than the code snippets I wrote in this ticket which may have errors. |
Example with multiple pagers on the same node: https://github.com/jimafisk/plenti_multi-pager_example |
There are some Svelte pagination packages you could pull into your project, but swyx makes a good point in the first comment about the issues of loading all pages clientside: https://www.reddit.com/r/sveltejs/comments/did1fr/sveltepaginate_paginate_your_data_in_no_time/. This brings up good points about how we're bundling all page content in the first place, but that's an optimization for a different thread.
Another issue is that if you simply looped through
allContent
(and possibly filtered it) you would not get static html fallbacks for pages beyond the first landing page. Plenti at the moment doesn't know how to SSR those subsequent sections of a list to display additional items. Hugo has a custom implementation for something like this https://gohugo.io/templates/pagination/I'd like to keep the scaffolding minimal and give folks the ability to do their own custom pagination. I'm thinking it would be best to extend the routing overrides in
plenti.json
to allow something like this:Where the first argument is the filter and the second is the number of items per page (e.g. if there are 50 total items and you pass 10 as the number of items per page, then there will be 5 total pages). The filters should be able to be combine like
content.type == 'blog' && content.fields.publish == true
. That would allow me write some logic behind the scenes incmd/build/data_source.go
to create newpublic/spa/ejected/content.js
entries for the same content source but with an incremented path, like:/blog
/blog/1
/blog/2
/blog/3
/blog/4
/blog/5
The remaining task would be setting the current page value in the svelte template. You could get this from the URL, but we would want it during SSR as well in order to set up each HTML fallback page with the correct values. We could extend the API above ^ to include an argument for the variable name that's used to represent the current page from the Svelte template... it does seem like we're getting awfully close to forcing the user to duplicate their pagination logic for the server and the browser though. Maybe there's a simpler / more elegant way to do this?
The text was updated successfully, but these errors were encountered: