Skip to content

Commit

Permalink
Kaminari pagination default view (#42)
Browse files Browse the repository at this point in the history
* Use values in forms

* Use form builder methods

* Some refactoring

* Add anyway-config

* Add Tailwind-styled pagination

* Add tailwind-styled pagination

* Make default pagination by configuration

* Add pagination config tests

* Add pagination tests

* Remove unused test

* Update README.md

* Minor updates

* Remove fixing on anyway_config version

* Remove empty lines in Gemfile

* Ordered gems

* Little fix
  • Loading branch information
kalashnikovisme authored Jan 20, 2024
1 parent 66f77e6 commit a9e5536
Show file tree
Hide file tree
Showing 22 changed files with 242 additions and 51 deletions.
3 changes: 3 additions & 0 deletions .reek.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@ detectors:
- "Tailwinds::Form::Builder"

directories:
"spec/dummy/app/controllers":
IrresponsibleModule:
enabled: false
"spec/dummy/db/migrate/":
FeatureEnvy:
enabled: false
Expand Down
12 changes: 5 additions & 7 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@ git_source(:github) { |repo| "https://github.com/#{repo}.git" }
# Specify your gem's dependencies in tramway.gemspec.
gemspec

gem 'anyway_config'
gem 'dry-initializer'
gem 'haml-rails'
gem 'kaminari'
gem 'puma'

gem 'sqlite3'

gem 'sprockets-rails'

gem 'haml-rails'

gem 'dry-initializer'
gem 'sqlite3'

group :development do
gem 'reek'
Expand Down
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Unite Ruby on Rails brilliance. Streamline development with Tramway.
* [Tramway Form](https://github.com/Purple-Magic/tramway#tramway-form)
* [Tramway Navbar](https://github.com/Purple-Magic/tramway#tramway-navbar)
* [Tailwind-styled forms](https://github.com/Purple-Magic/tramway#tailwind-styled-forms)
* [Tailwind-styled pagination](https://github.com/Purple-Magic/tramway#tailwind-styled-pagination)

## Installation
Add this line to your application's Gemfile:
Expand Down Expand Up @@ -362,13 +363,40 @@ Available form helpers:
* select
* submit

### Tailwind-styled pagination for Kaminari

Tramway uses [Tailwind](https://tailwindcss.com/) by default. It has tailwind-styled pagination for [kaminari](https://github.com/kaminari/kaminari).

#### How to use

*Gemfile*
```ruby
gem 'tramway'
gem 'kaminari'
```

*config/initializers/tramway.rb*
```ruby
Tramway.configure do |config|
config.pagination = { enabled: true } # enabled is false by default
end
```

*app/views/users/index.html.haml*
```haml
= paginate @users # it will render tailwind-styled pagination buttons by default
```

Pagination buttons looks like [this](https://play.tailwindcss.com/mqgDS5l9oY)

## Contributing

Install [lefthook](https://github.com/evilmartians/lefthook)

```
bundle
lefthook install
rspec
```
## License
Expand Down
9 changes: 9 additions & 0 deletions app/views/kaminari/_first_page.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-# Link to the "First" page
-# available local variables
-# url: url to the first page
-# current_page: a page object for the currently displayed page
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%span.first{ class: 'px-3 py-2 text-sm font-medium text-purple-700 bg-white rounded-md hover:bg-purple-100' }
= link_to_unless current_page.first?, t('views.pagination.first').html_safe, url, remote: remote
8 changes: 8 additions & 0 deletions app/views/kaminari/_gap.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
-# Non-link tag that stands for skipped pages...
-# available local variables
-# current_page: a page object for the currently displayed page
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%span.page.gap{ class: 'px-3 py-2 text-sm font-medium text-purple-700' }
= t('views.pagination.truncate').html_safe
9 changes: 9 additions & 0 deletions app/views/kaminari/_last_page.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-# Link to the "Last" page
-# available local variables
-# url: url to the last page
-# current_page: a page object for the currently displayed page
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%span.last{ class: 'px-3 py-2 text-sm font-medium text-purple-700 bg-white rounded-md hover:bg-purple-100' }
= link_to_unless current_page.last?, t('views.pagination.last').html_safe, url, remote: remote
9 changes: 9 additions & 0 deletions app/views/kaminari/_next_page.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-# Link to the "Next" page
-# available local variables
-# url: url to the next page
-# current_page: a page object for the currently displayed page
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%span.next{ class: 'px-3 py-2 text-sm font-medium text-purple-700 bg-white rounded-md hover:bg-purple-100' }
= link_to_unless current_page.last?, t('views.pagination.next').html_safe, url, rel: 'next', remote: remote
14 changes: 14 additions & 0 deletions app/views/kaminari/_page.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
-# Link showing page number
-# available local variables
-# page: a page object for "this" page
-# url: url to this page
-# current_page: a page object for the currently displayed page
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
- if page.current?
%span{class: "px-3 py-2 font-medium rounded-md bg-purple-500 text-white" }
= page
- else
%span{class: "cursor px-3 py-2 font-medium text-purple-700 bg-white rounded-md hover:bg-purple-100"}
= link_to_unless page.current?, page, url, {remote: remote, rel: page.rel}
12 changes: 12 additions & 0 deletions app/views/kaminari/_paginator.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
= paginator.render do
%nav.pagination.flex.items-center.justify-center.space-x-1
= first_page_tag unless current_page.first?
= prev_page_tag unless current_page.first?
- each_page do |page|
- if page.display_tag?
= page_tag page
- elsif !page.was_truncated?
= gap_tag
= next_page_tag unless current_page.last?
= last_page_tag unless current_page.last?

9 changes: 9 additions & 0 deletions app/views/kaminari/_prev_page.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
-# Link to the "Previous" page
-# available local variables
-# url: url to the previous page
-# current_page: a page object for the currently displayed page
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%span.prev{ class: 'px-3 py-2 text-sm font-medium text-purple-700 bg-white rounded-md hover:bg-purple-100' }
= link_to_unless current_page.first?, t('views.pagination.previous').html_safe, url, rel: 'prev', remote: remote
16 changes: 8 additions & 8 deletions lib/tramway/config.rb
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
# frozen_string_literal: true

require 'anyway'
require 'singleton'
require 'tramway/configs/entity'

module Tramway
# Basic configuration of Tramway
#
class Config
class Config < Anyway::Config
include Singleton

def initialize
@entities = []
end
attr_config(
pagination: { enabled: false },
entities: []
)

def entities=(collection)
@entities = collection.map do |entity|
super(collection.map do |entity|
entity_options = entity.is_a?(Hash) ? entity : { name: entity }

Tramway::Configs::Entity.new(**entity_options)
end
end)
end

attr_reader :entities
end
end
36 changes: 36 additions & 0 deletions lib/tramway/engine.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,65 @@ class Engine < ::Rails::Engine
isolate_namespace Tramway

initializer 'tramway.load_helpers' do
load_navbar_helper
load_views_helper
load_decorator_helper
load_form_helper
configure_pagination if Tramway.config.pagination[:enabled]
end

private

def load_navbar_helper
ActiveSupport.on_load(:action_view) do |loaded_class|
require 'tramway/helpers/navbar_helper'

loaded_class.include Tramway::Helpers::NavbarHelper
end
end

def load_views_helper
ActiveSupport.on_load(:action_view) do |loaded_class|
require 'tramway/helpers/views_helper'

loaded_class.include Tramway::Helpers::ViewsHelper
end
end

def load_decorator_helper
ActiveSupport.on_load(:action_controller) do |loaded_class|
require 'tramway/helpers/decorate_helper'

loaded_class.include Tramway::Helpers::DecorateHelper
end
end

def load_form_helper
ActiveSupport.on_load(:action_controller) do |loaded_class|
require 'tramway/helpers/form_helper'

loaded_class.include Tramway::Helpers::FormHelper
end
end

# :reek:NestedIterators { enabled: false }
# :reek:TooManyStatements { enabled: false }
def configure_pagination
ActiveSupport.on_load(:action_controller) do
# Detecting tramway views path
tramway_spec = Gem.loaded_specs['tramway']
tramway_views_path = File.join(tramway_spec.full_gem_path, 'app/views')

paths = view_paths.to_ary

# Determine index to insert tramway views path
rails_views_index = paths.find_index { |path| path.to_s.ends_with?('app/views') }
insert_index = rails_views_index ? rails_views_index + 1 : 0

# Inserting tramway views path
paths.insert(insert_index, tramway_views_path)
self.view_paths = paths
end
end
end
end
7 changes: 7 additions & 0 deletions spec/dummy/app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

class UsersController < ApplicationController
def index
@users = User.all.page(params[:page])
end
end
4 changes: 4 additions & 0 deletions spec/dummy/app/views/users/_user.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
%tr
- [:email].each do |attribute|
%td.py-2.px-4.border-b.border-r
= user.public_send(attribute)
14 changes: 14 additions & 0 deletions spec/dummy/app/views/users/index.html.haml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.flex.justify-between.mb-4.mt-4
%h1{ class: "text-4xl font-bold text-left text-black-700 mb-8 mt-4" }
= t('activerecord.plural.models.user.many')
%table.w-full.bg-white.border.border-gray-200
%thead
%tr
- [:email].each do |attribute|
%th.py-2.px-4.border-b.border-r
= User.human_attribute_name attribute
%tbody#users
= render @users
.flex.flex-end.border-t.border-gray-200.px-4.pt-4.w-full
= paginate @users
2 changes: 2 additions & 0 deletions spec/dummy/config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ class Application < Rails::Application
# For compatibility with applications that use this config
config.action_controller.include_all_helpers = false

config.hosts << 'www.example.com'

# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
Expand Down
5 changes: 5 additions & 0 deletions spec/dummy/config/initializers/tramway.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

Tramway.configure do |config|
config.pagination = { enabled: true }
end
38 changes: 6 additions & 32 deletions spec/dummy/config/locales/en.yml
Original file line number Diff line number Diff line change
@@ -1,33 +1,7 @@
# Files in the config/locales directory are used for internationalization
# and are automatically loaded by Rails. If you want to use locales other
# than English, add the necessary files in this directory.
#
# To use the locales, use `I18n.t`:
#
# I18n.t "hello"
#
# In views, this is aliased to just `t`:
#
# <%= t("hello") %>
#
# To use a different locale, set it with `I18n.locale`:
#
# I18n.locale = :es
#
# This would use the information in config/locales/es.yml.
#
# The following keys must be escaped otherwise they will not be retrieved by
# the default I18n backend:
#
# true, false, on, off, yes, no
#
# Instead, surround them with single quotes.
#
# en:
# "true": "foo"
#
# To learn more, please read the Rails Internationalization guide
# available at https://guides.rubyonrails.org/i18n.html.

en:
hello: "Hello world"
views:
pagination:
first: First
last: Last
next: Next
previous: Previous
2 changes: 0 additions & 2 deletions spec/dummy/config/routes.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
# frozen_string_literal: true

Rails.application.routes.draw do
mount Tramway::Engine => '/tramway'

resources :users
resources :clients

Expand Down
43 changes: 43 additions & 0 deletions spec/pagination/render_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

shared_examples 'Click on Page' do |page_number, text = nil|
it "navigates to the correct #{text || page_number} page link is clicked" do
visit users_path

within 'nav.pagination', match: :first do
click_link text || page_number
end

expect(page).to have_current_path(users_path(page: page_number))
end
end

feature 'Order Index Page', type: %i[feature admin] do
context 'check pagination' do
before do
User.destroy_all
create_list :user, 125
end

it 'displays 1..5 pages links and next/last buttons' do
visit users_path

expect(page).to have_css('span', text: '1', class: 'bg-purple-500')

(2..5).each do |i|
expect(page).to have_link(i.to_s, href: users_path(page: i))
end

expect(page).to have_link('Next', href: users_path(page: 2))

expect(page).to have_link('Last', href: users_path(page: 5))
end

include_examples 'Click on Page', '2'
include_examples 'Click on Page', '3'
include_examples 'Click on Page', '4'
include_examples 'Click on Page', '5'
include_examples 'Click on Page', '2', 'Next'
include_examples 'Click on Page', '5', 'Last'
end
end
Loading

0 comments on commit a9e5536

Please sign in to comment.