# frozen_string_literal: true
# Interactive showcase for all the pagy helpers and CSS styles
# DEMO USAGE
# pagy demo
# DEV USAGE
# pagy clone demo
# pagy ./demo.ru
# URL
# http://0.0.0.0:8000
# HELP
# pagy -h
# DOC
# https://ddnexus.github.io/pagy/playground/#3-demo-app
VERSION = '8.1.1'
require 'bundler/inline'
gemfile(true) do
source 'https://rubygems.org'
gem 'oj'
gem 'puma'
gem 'rouge'
gem 'sinatra'
gem 'sinatra-contrib'
end
# pagy initializer
STYLES = { pagy: { extra: 'pagy', prefix: '', css_anchor: 'pagy-scss' },
bootstrap: {},
bulma: {},
foundation: {},
materialize: {},
semantic: {},
tailwind: { extra: 'pagy', prefix: '', css_anchor: 'pagy-tailwind-css' },
uikit: {} }.freeze
STYLES.each_key do |style|
require "pagy/extras/#{STYLES[style][:extra] || style}"
end
require 'pagy/extras/items'
require 'pagy/extras/trim'
Pagy::DEFAULT[:trim_extra] = false # opt-in trim
Pagy::DEFAULT[:size] = [1, 4, 4, 1] # old size default
# sinatra setup
require 'sinatra/base'
# sinatra application
class PagyDemo < Sinatra::Base
configure do
enable :inline_templates
end
include Pagy::Backend
get '/' do
redirect '/pagy'
end
get '/template' do
collection = MockCollection.new
@pagy, @records = pagy(collection, trim_extra: params['trim'])
erb :template, locals: { pagy: @pagy, style: 'pagy' }
end
get('/javascripts/:file') do
content_type 'application/javascript'
send_file Pagy.root.join('javascripts', params[:file])
end
get('/stylesheets/:file') do
content_type 'text/css'
send_file Pagy.root.join('stylesheets', params[:file])
end
# one route/action per style
STYLES.each_key do |style|
prefix = STYLES[style][:prefix] || "_#{style}"
get("/#{style}/?:trim?") do
collection = MockCollection.new
@pagy, @records = pagy(collection, trim_extra: params['trim'])
erb :helpers, locals: { style:, prefix: }
end
end
helpers do
include Pagy::Frontend
def style_menu
html = +%(
)
STYLES.each_key { |style| html << %(#{style}) }
html << %(template)
html << %(
)
end
def highlight(html, format: :html)
if format == :html
html = html.gsub(/>[\s]*, '><').strip # template single line no spaces around/between tags
html = Formatter.new.format(html)
end
lexer = Rouge::Lexers::ERB.new
formatter = Rouge::Formatters::HTMLInline.new('monokai.sublime')
summary = { html: 'Served HTML (pretty formatted)', erb: 'ERB Template' }
%(#{summary[format]}
\n#{
formatter.format(lexer.lex(html))
}
)
end
end
end
# Cheap pagy formatter for helpers output
class Formatter
INDENT = ' '
TEXT_SPACE = "\u00B7"
TEXT = /^([^<>]+)(.*)/
UNPAIRED = /^(<(input|link).*?>)(.*)/
PAIRED = %r{^(<(head|nav|div|span|p|a|b|label|ul|li).*?>)(.*?)(\2>)(.*)}
WRAPPER = /<.*?>/
DATA_PAGY = /(data-pagy="([^"]+)")/
def initialize
@formatted = +''
end
def format(input, level = 0)
process(input, level)
@formatted
end
private
def process(input, level)
push = ->(content) { @formatted << ((INDENT * level) << content << "\n") }
rest = nil
if (match = input.match(TEXT))
text, rest = match.captures
push.(text.gsub(' ', TEXT_SPACE))
elsif (match = input.match(UNPAIRED))
tag, _name, rest = match.captures
push.(tag)
elsif (match = input.match(PAIRED))
tag_start, name, block, tag_end, rest = match.captures
## Handle incomplete same-tag nesting
while block.scan(/<#{name}.*?>/).size > block.scan(tag_end).size
more, rest = rest.split(tag_end, 2)
block << tag_end << more
end
if (match = tag_start.match(DATA_PAGY))
search, data = match.captures
formatted = data.scan(/.{1,76}/).join("\n")
replace = %(\n#{INDENT * (level + 1)}data-pagy="#{formatted}")
tag_start.sub!(search, replace)
end
if block.match(WRAPPER)
push.(tag_start)
process(block, level + 1)
push.(tag_end)
else
push.(tag_start << block << tag_end)
end
end
process(rest, level) if rest
end
end
# Simple array-based collection that acts as a standard DB collection.
class MockCollection < Array
def initialize(arr = Array(1..1000))
super
@collection = clone
end
def offset(value)
@collection = self[value..]
self
end
def limit(value)
@collection[0, value]
end
def count(*)
size
end
end
run PagyDemo
# We store the template in a constant instead of writing it inline, so we can highlight it more easily
TEMPLATE = <<~ERB
<%# IMPORTANT: use '<%== ... ' instead of '<%= ... ' if you run this in rails %>
<%# The a variable below is set to a lambda that generates the a tag %>
<%# Usage: a_tag = a.(page_number, text, classes: nil, aria_label: nil) %>
<% a = pagy_anchor(pagy) %>
ERB
__END__
@@ layout
Pagy Demo App
<%= erb :"#{style}_head" if defined?(style) %>
<%= style_menu %>
<%# We don't inline the template here, so we can highlight it more easily %>
<%= html = ERB.new(TEMPLATE).result(binding) %>
<%= highlight(TEMPLATE, format: :erb) %>
<%= highlight(html) %>