Open onno-timmerman opened 5 months ago
As an addition, if we want to add this, I think it would be useful to allow the user to input a specific page number to jump to.
This needs some UI designs before it can be implemented, though.
Jeroen is working on this during Wagtail Space NL 2024, if we have a PR ready with the technical implementation, we always improve the styling/design later.
Is this being worked on already? If not, I would be happy to submit a PR with a version of this that I've built.
I currently have a subclassed generic.IndexView
where I added Django's get_elided_page_range
to the pagination setup. By default, the first two and last two page numbers are included, as well as three pages beside the current page. If the numbers aren't continuous, an ellipsis is added between the sets of numbers.
I kept and bolded "Page X" for the current page to help emphasise it, and dropped the "of Y." since the last page number is always in view at the end.
Here are a few screenshots:
On 2 of 18:
On 10 of 18:
On the last page:
@jordanmt from @allcaps’ message it sounds like someone else might have an implementation under way?
We do have target designs for this, here is a screenshot:
I’m not sure how much we’ve considered different options on the emphasis and number of pages to show on the two sides of the ellipsis, will make sure to bring this up in our next UI design meeting.
@thibaudcolas Could I suggest including #11988 (adding an 'items per page' selector) as part of that discussion? Personally I'm not sold on it (it's adding extra UI controls for micromanaging a detail that users shouldn't have to care about) but it'd be good to have a definitive yes or no.
I think Jeroens efforts during Wagtail Space NL are not continued. So please go ahead.
I'll work on this further using the target designs. They look well thought out! I think I'll start it with 1 number on the ends and 2 on the sides and do a closer review on how it looks on different page sizes than I did earlier. I'll also keep an eye out for any further UI discussion.
Three design questions for @benenright to review:
Hi
I have made some adjustments based on the comments above:
Thank you @benenright, do you have thoughts on the options we should offer under "Items per page"?
For your proposed designs, as-is it seems like the position of the buttons would move around horizontally as you go from page to page – would it be possible to change the designs so they’re more predictable? For example if I start on page 1 and want to go to page 5, it would be nice if the "Next" button was at the same place on the horizontal axis, so I just have to scroll back down to it and click.
I'd like the 'Items per page' to be defined in code. I think deciding the length of a list is a developer decision. Not something a user should have control over.
The wait for too many items might be annoying for the user, for the hosting platform it might fail to generate a too big response.
Maybe it is me, but I just don't see big UX benefits. What does the user gain? After say 50 items, it is an impractical long list anyway.
Slight update to address Thibaud's comment above:
We probably want to use Django's get_elided_page_range
here to avoid reinventing the wheel, and if we do, we can't enforce that there will always be exactly 6 buttons. As long as that block as a whole is centred, though, I think that's good enough...?
Slight update to address Thibaud's comment above:
- use some logic to ensure there are always 6 buttons between next/prev (inc. ellipses where needed to show skipped pages)
- this means the next/prev and first/last page buttons will always remain in the same position on the horizontal axis
This is looking nice 🧽✨
I've built an initial version of this and wanted to share progress and a look at two options. The first is using Django's Paginator.get_elided_page_range with on_each_side
and on_ends
params set to 1, and the second uses a custom page range.
Using get_elided_page_range from Django's Paginator This on is simple on the Python side. We just need to add get_elided_page_range into the page context so that we can use it in templates (i.e. pagination_nav.html).
https://github.com/user-attachments/assets/56a9ae04-f730-4312-8fe3-41136e045a0d
Using a custom page range that ensures 6 positions
This requires more code, but personally I like the consistency along the horizontal axis. You'll see a small shift in this video clip when previous/next show or hide because I haven't perfected the layout yet. Here I am setting paginator_class
on BaseListingView to use a Django Paginator subclass with an added custom range function. The function is basically a simplified version of the Django one, assembling the ranges + ellipses in a way that ensures 6 positions.
https://github.com/user-attachments/assets/f902583c-7acf-4f70-88db-2270707e4c36
I'll work on cleaning up the second approach so that the code can be evaluated for any trade offs, and it'll be easy to go back to the first option if that seems best. I'm also going to look at a setting for the paginator class so that it's easier for developers to customize at a high level.
Great work. Looks really good.
Just wondering, does that second example not depend on word length? What if those words are longer or shorter in some languages? Does this still work? We should consider the shortest and longest translations to validate the 'staying in place'.
And does a visible, but disabled previous and disabled next not prevent jumping? Maybe it is not designed that way, but it is a pretty common solution. The disabled buttons could also be styled to have little visual impact. Just occupy the space.
My plan was to use the translated string to maintain the same widths across pages, using visibility: hidden;
. I think this is an acceptable approach but I should double check the accessibility implications (I believe it will be hidden from screen readers as well, which would be the goal).
This was my approach:
{% if items.has_previous %}
<a href="{{ url_path }}{% querystring p=items.previous_page_number %}">
{% icon name="arrow-left" classname="default" %}
{% trans 'Previous' %}
</a>
{% else %}
<span style="visibility: hidden;"> <!-- doesn't need to be inline CSS, but added here to illustrate -->
{% icon name="arrow-left" classname="default" %}
{% trans 'Previous' %}
</span>
{% endif %}
The issue causing shifting in my video is that I didn't have the icon repeated in the span in this example, only the text. So it was off by about 20px. Now it's totally smooth :).
But, thinking about this further: an A element with the href omitted is OK, so I think we can do something more concise and maintainable (less chance of the span and a elements varying in styling) like this:
<a{% if items.has_previous %} href="{{ url_path }}{% querystring p=items.previous_page_number %}"{% endif %}>
{% icon name="arrow-left" classname="default" %}
{% trans 'Previous' %}
</a>
And just select for a elements without href:
.pagination li a:not([href]) {
visibility: hidden;
}
That looks neat. I like that the "next" and "previous" links stay in place.
To make the links stay in place even if the other one is not shown, could you maybe use flex
or grid
to define containers in which the links are shown when they are needed?
Wow! this looks great, and thank you for taking the time to provide the update. Your custom version does seem much smoother.
Re word lengths, I would assume it should be no problem as long as we text-align: end
the left label, and text-align: start
the right label. Or the flex
/ grid options that Tibor mentions. Happy to take more of a look once the PR is there!
Is your proposal related to a problem?
Admin complains in a project that the pagination is not usable in Wagtail admin. It only give you "next page" and "prev page" This is annoying if you have 1000+ items and want to brouwse in it. Explaining that you can change the url to jump is very userfriendly :)
Describe the solution you'd like
Normal usable pagination at the bottom in the form <<<< first page 1, 2, 3, 4, 5, 6 ... 1000, 1001, 1002 - last page >>>