feat: add pagination to cities and arts index

- Implement pagination for the cities index view.
- Add shared pagination partial to reduce code duplication.
- Modify arts index view to utilize the new pagination.
- Update cities controller to include pagination logic.

These updates improve usability by allowing better navigation through larger datasets, ensuring users can easily access and view items across multiple pages.
This commit is contained in:
songtianlun 2025-01-23 17:30:05 +08:00
parent a4de04874d
commit f33fb4d2ba
4 changed files with 152 additions and 80 deletions

View File

@ -1,6 +1,5 @@
class CitiesController < ApplicationController
def index
@cities = City.all.order(:name)
@regions = Region.includes(:countries).order(:name)
@cities = City.includes(:country, country: :region).active.order(:name)
@ -13,6 +12,8 @@ class CitiesController < ApplicationController
@current_country = Country.friendly.find(params[:country])
@cities = @cities.by_country(@current_country.id)
end
@cities = @cities.page(params[:page]).per(10)
end
def show

View File

@ -101,21 +101,17 @@
</div>
</div>
<!-- 图片网格 -->
<div class="container mx-auto px-4 pb-16">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-6">
<% @weather_arts.each do |art| %>
<div class="card bg-base-100 shadow-xl hover:shadow-2xl transition-all duration-300 group overflow-hidden">
<!-- 图片部分 -->
<figure class="relative aspect-square overflow-hidden">
<% if art.image.attached? %>
<%= image_tag art.image,
class: "w-full h-full object-cover transform group-hover:scale-105 transition-transform duration-500" %>
<!-- 渐变遮罩 -->
<div class="absolute inset-0 bg-gradient-to-t from-black via-black/50 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-300"></div>
<!-- 悬停信息 -->
<div class="absolute inset-0 p-6 flex flex-col justify-end translate-y-4 opacity-0 group-hover:translate-y-0 group-hover:opacity-100 transition-all duration-300">
<div class="text-white space-y-2">
<h3 class="text-xl font-display font-bold">
@ -168,20 +164,9 @@
<% end %>
</div>
<!-- 分页 -->
<% if @weather_arts.total_pages > 1 %>
<div class="flex justify-center mt-12">
<div class="btn-group">
<%= link_to_prev_page @weather_arts, "Previous",
class: "btn btn-outline #{'btn-disabled' unless @weather_arts.prev_page}" %>
<% @weather_arts.total_pages.times do |i| %>
<%= link_to i + 1, arts_path(page: i + 1, region: params[:region], sort: params[:sort]),
class: "btn btn-outline #{'btn-active' if @weather_arts.current_page == i + 1}" %>
<% end %>
<%= link_to_next_page @weather_arts, "Next",
class: "btn btn-outline #{'btn-disabled' unless @weather_arts.next_page}" %>
<%= render 'shared/pagination',
collection: @weather_arts,
collection_name: 'weather arts' %>
</div>
</div>
<% end %>
</div>
</div>

View File

@ -12,7 +12,6 @@
</div>
<% end %>
<!-- 标题内容 -->
<div class="relative pt-24 pb-32">
<div class="container mx-auto px-4">
<div class="max-w-3xl mx-auto text-center space-y-6">
@ -38,13 +37,10 @@
</div>
</div>
<!-- 筛选导航 - 使用下拉菜单 -->
<div class="sticky top-16 z-20 bg-base-100/95 backdrop-blur-sm border-b border-base-200">
<div class="container mx-auto px-4">
<div class="py-3 flex items-center justify-between gap-4">
<!-- 左侧筛选器 -->
<div class="flex items-center gap-4">
<!-- 区域选择下拉框 -->
<div class="dropdown">
<button class="btn btn-ghost gap-2">
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
@ -73,7 +69,6 @@
</ul>
</div>
<!-- 国家选择下拉框 (如果选择了区域) -->
<% if @current_region %>
<div class="dropdown">
<button class="btn btn-ghost gap-2">
@ -104,7 +99,6 @@
<% end %>
</div>
<!-- 右侧结果统计 -->
<div class="text-sm text-base-content/70">
<%= @cities.count %> <%= 'city'.pluralize(@cities.count) %>
<% if @current_country %>
@ -117,10 +111,16 @@
</div>
</div>
<!-- 城市网格 -->
<div class="container mx-auto px-4 py-8">
<div class="container mx-auto px-4 pb-16">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
<%= render partial: 'city', collection: @cities %>
</div>
<%= render 'shared/pagination',
collection: @cities,
collection_name: 'cities' %>
</div>
</div>
</div>

View File

@ -0,0 +1,86 @@
<%# app/views/shared/_pagination.html.erb %>
<% if collection.total_pages > 1 %>
<div class="flex flex-col items-center mt-16 gap-6">
<!-- 页码信息 -->
<div class="text-base-content/70 font-light">
<span class="px-4 py-2 bg-base-200/50 rounded-full">
Page <%= collection.current_page %> of <%= collection.total_pages %>
</span>
</div>
<!-- 分页控件 -->
<div class="join shadow-lg">
<!-- 首页 -->
<%= link_to url_for(page: 1, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn #{collection.first_page? ? 'btn-disabled' : 'btn-ghost'}" do %>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 19l-7-7 7-7m8 14l-7-7 7-7" />
</svg>
<% end %>
<!-- 上一页 -->
<%= link_to url_for(page: collection.prev_page || 1, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn #{collection.first_page? ? 'btn-disabled' : 'btn-ghost'}" do %>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
</svg>
<% end %>
<!-- 页码 -->
<% page_window = 2 # 当前页面前后显示的页码数 %>
<% start_page = [1, collection.current_page - page_window].max %>
<% end_page = [collection.total_pages, collection.current_page + page_window].min %>
<% if start_page > 1 %>
<%= link_to 1, url_for(page: 1, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn btn-ghost hover:bg-primary/5" %>
<% if start_page > 2 %>
<button class="join-item btn btn-ghost btn-disabled">...</button>
<% end %>
<% end %>
<% (start_page..end_page).each do |page| %>
<% if page == collection.current_page %>
<button class="join-item btn btn-ghost bg-primary/10 font-medium">
<%= page %>
</button>
<% else %>
<%= link_to page, url_for(page: page, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn btn-ghost hover:bg-primary/5" %>
<% end %>
<% end %>
<% if end_page < collection.total_pages %>
<% if end_page < collection.total_pages - 1 %>
<button class="join-item btn btn-ghost btn-disabled">...</button>
<% end %>
<%= link_to collection.total_pages,
url_for(page: collection.total_pages, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn btn-ghost hover:bg-primary/5" %>
<% end %>
<!-- 下一页 -->
<%= link_to url_for(page: collection.next_page || collection.total_pages, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn #{collection.last_page? ? 'btn-disabled' : 'btn-ghost'}" do %>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
</svg>
<% end %>
<!-- 末页 -->
<%= link_to url_for(page: collection.total_pages, region: params[:region], country: params[:country], sort: params[:sort]),
class: "join-item btn #{collection.last_page? ? 'btn-disabled' : 'btn-ghost'}" do %>
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 5l7 7-7 7M5 5l7 7-7 7" />
</svg>
<% end %>
</div>
<!-- 结果统计 -->
<div class="text-sm text-base-content/60 font-light">
Showing <%= collection.offset_value + 1 %> to
<%= collection.last_page? ? collection.total_count : collection.offset_value + collection.limit_value %>
of <%= collection.total_count %> <%= collection_name || 'items' %>
</div>
</div>
<% end %>