better_ui 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/components/better_ui/table/column_component.rb +5 -2
- data/app/components/better_ui/table/concerns/sort_icons.rb +48 -0
- data/app/components/better_ui/table/header_cell_component/header_cell_component.html.erb +11 -2
- data/app/components/better_ui/table/header_cell_component.rb +13 -5
- data/app/components/better_ui/table/table_component/table_component.html.erb +7 -2
- data/app/components/better_ui/table/table_component.rb +59 -7
- data/lib/better_ui/version.rb +1 -1
- data/spec/components/previews/better_ui/table/table_component_preview/collection_mode.html.erb +4 -4
- data/spec/components/previews/better_ui/table/table_component_preview/highlighted.html.erb +4 -4
- data/spec/components/previews/better_ui/table/table_component_preview/row_html.html.erb +3 -3
- data/spec/components/previews/better_ui/table/table_component_preview/sortable.html.erb +45 -3
- data/spec/components/previews/better_ui/table/table_component_preview.rb +2 -0
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: aa5d4adee48517dabb8bd4b65018f8f05a5f9414e8ccbe46e7c0a6f833b735ba
|
|
4
|
+
data.tar.gz: b39c4dc0a95c7cca09807d27c88d6eba91fe480857bdb7d61dba1d2deb045cec
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ded2a724d33adb91e44c7551689ba1c492f6ccf353c603c7d388db48f009331b820159064d796d83a8095f52f03dd7fd9c863b8e27ddecffbfde281c39bc0203
|
|
7
|
+
data.tar.gz: c9f3fecbe32188a0bd8e5c23876a9638e960377337dcb42165c0cc0dc63762140eff6a98802c57a426d5586db1be71f006fa933951e898168226477f2206c6bc
|
|
@@ -21,10 +21,11 @@ module BetterUi
|
|
|
21
21
|
SORT_DIRECTIONS = %i[asc desc].freeze
|
|
22
22
|
|
|
23
23
|
attr_reader :key, :label, :align, :header_classes, :cell_classes, :formatter,
|
|
24
|
-
:sortable, :sorted, :sort_direction
|
|
24
|
+
:sortable, :sorted, :sort_direction, :sort_url, :sort_html
|
|
25
25
|
|
|
26
26
|
def initialize(key: nil, label: nil, align: :left, header_classes: nil, cell_classes: nil,
|
|
27
|
-
sortable: false, sorted: false, sort_direction: :asc,
|
|
27
|
+
sortable: false, sorted: false, sort_direction: :asc,
|
|
28
|
+
sort_url: nil, sort_html: {}, &formatter)
|
|
28
29
|
@key = key
|
|
29
30
|
@label = label
|
|
30
31
|
@align = validate_align(align)
|
|
@@ -33,6 +34,8 @@ module BetterUi
|
|
|
33
34
|
@sortable = sortable
|
|
34
35
|
@sorted = sorted
|
|
35
36
|
@sort_direction = validate_sort_direction(sort_direction)
|
|
37
|
+
@sort_url = sort_url
|
|
38
|
+
@sort_html = sort_html || {}
|
|
36
39
|
@formatter = formatter
|
|
37
40
|
end
|
|
38
41
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module BetterUi
|
|
4
|
+
module Table
|
|
5
|
+
module Concerns
|
|
6
|
+
# Shared SVG sort icon helpers for table header components.
|
|
7
|
+
#
|
|
8
|
+
# Provides three icon methods used by both TableComponent (collection mode)
|
|
9
|
+
# and HeaderCellComponent (slot mode) to render sort direction indicators.
|
|
10
|
+
module SortIcons
|
|
11
|
+
extend ActiveSupport::Concern
|
|
12
|
+
|
|
13
|
+
private
|
|
14
|
+
|
|
15
|
+
# SVG chevron-up icon for ascending sort
|
|
16
|
+
def sort_icon_asc_svg
|
|
17
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4">' \
|
|
18
|
+
'<path fill-rule="evenodd" d="M11.78 9.78a.75.75 0 0 1-1.06 0L8 7.06 5.28 9.78a.75.75 0 0 1-1.06-1.06l3.25-3.25a.75.75 0 0 1 1.06 0l3.25 3.25a.75.75 0 0 1 0 1.06Z" clip-rule="evenodd" />' \
|
|
19
|
+
"</svg>"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# SVG chevron-down icon for descending sort
|
|
23
|
+
def sort_icon_desc_svg
|
|
24
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4">' \
|
|
25
|
+
'<path fill-rule="evenodd" d="M4.22 6.22a.75.75 0 0 1 1.06 0L8 8.94l2.72-2.72a.75.75 0 1 1 1.06 1.06l-3.25 3.25a.75.75 0 0 1-1.06 0L4.22 7.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />' \
|
|
26
|
+
"</svg>"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# SVG chevron-up-down icon for unsorted state
|
|
30
|
+
def sort_icon_unsorted_svg
|
|
31
|
+
'<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="currentColor" class="size-4">' \
|
|
32
|
+
'<path fill-rule="evenodd" d="M5.22 10.22a.75.75 0 0 1 1.06 0L8 11.94l1.72-1.72a.75.75 0 1 1 1.06 1.06l-2.25 2.25a.75.75 0 0 1-1.06 0l-2.25-2.25a.75.75 0 0 1 0-1.06ZM10.78 5.78a.75.75 0 0 1-1.06 0L8 4.06 6.28 5.78a.75.75 0 0 1-1.06-1.06l2.25-2.25a.75.75 0 0 1 1.06 0l2.25 2.25a.75.75 0 0 1 0 1.06Z" clip-rule="evenodd" />' \
|
|
33
|
+
"</svg>"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Returns the appropriate sort icon SVG for the given sort state
|
|
37
|
+
def sort_icon_svg(sorted:, direction: :asc)
|
|
38
|
+
return sort_icon_unsorted_svg unless sorted
|
|
39
|
+
|
|
40
|
+
case direction
|
|
41
|
+
when :asc then sort_icon_asc_svg
|
|
42
|
+
when :desc then sort_icon_desc_svg
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
<th class="<%= component_classes %>"<% if @scope %> scope="<%= @scope %>"<% end %> <%= tag.attributes(@options) %>>
|
|
2
|
-
<% if
|
|
2
|
+
<% if sort_link? %>
|
|
3
|
+
<%= link_to @sort_url, **sort_link_html, class: "flex items-center gap-1 no-underline text-inherit" do %>
|
|
4
|
+
<% if @label.present? %>
|
|
5
|
+
<%= @label %>
|
|
6
|
+
<% else %>
|
|
7
|
+
<%= content %>
|
|
8
|
+
<% end %>
|
|
9
|
+
<span class="<%= sort_icon_classes %>"><%= raw sort_icon %></span>
|
|
10
|
+
<% end %>
|
|
11
|
+
<% elsif @sortable %>
|
|
3
12
|
<span class="flex items-center gap-1">
|
|
4
13
|
<% if @label.present? %>
|
|
5
14
|
<%= @label %>
|
|
6
15
|
<% else %>
|
|
7
16
|
<%= content %>
|
|
8
17
|
<% end %>
|
|
9
|
-
<span class="<%= sort_icon_classes %>"><%= sort_icon %></span>
|
|
18
|
+
<span class="<%= sort_icon_classes %>"><%= raw sort_icon %></span>
|
|
10
19
|
</span>
|
|
11
20
|
<% else %>
|
|
12
21
|
<% if @label.present? %>
|
|
@@ -13,6 +13,7 @@ module BetterUi
|
|
|
13
13
|
# @example Header cell with block content
|
|
14
14
|
# <%= render BetterUi::Table::HeaderCellComponent.new(align: :right) { "Actions" } %>
|
|
15
15
|
class HeaderCellComponent < ApplicationComponent
|
|
16
|
+
include Concerns::SortIcons
|
|
16
17
|
SIZES = {
|
|
17
18
|
xs: { padding: "px-2 py-1.5", text: "text-xs" },
|
|
18
19
|
sm: { padding: "px-3 py-2", text: "text-sm" },
|
|
@@ -26,6 +27,7 @@ module BetterUi
|
|
|
26
27
|
|
|
27
28
|
def initialize(label: nil, align: :left, size: :md, style: :default, scope: :col,
|
|
28
29
|
variant: :primary, sortable: false, sorted: false, sort_direction: :asc,
|
|
30
|
+
sort_url: nil, sort_html: {},
|
|
29
31
|
container_classes: nil, **options)
|
|
30
32
|
@label = label
|
|
31
33
|
@align = validate_align(align)
|
|
@@ -36,6 +38,8 @@ module BetterUi
|
|
|
36
38
|
@sortable = sortable
|
|
37
39
|
@sorted = sorted
|
|
38
40
|
@sort_direction = validate_sort_direction(sort_direction)
|
|
41
|
+
@sort_url = sort_url
|
|
42
|
+
@sort_html = sort_html || {}
|
|
39
43
|
@container_classes = container_classes
|
|
40
44
|
@options = options
|
|
41
45
|
end
|
|
@@ -84,12 +88,8 @@ module BetterUi
|
|
|
84
88
|
|
|
85
89
|
def sort_icon
|
|
86
90
|
return nil unless @sortable
|
|
87
|
-
return "↕" unless @sorted
|
|
88
91
|
|
|
89
|
-
|
|
90
|
-
when :asc then "↑"
|
|
91
|
-
when :desc then "↓"
|
|
92
|
-
end
|
|
92
|
+
sort_icon_svg(sorted: @sorted, direction: @sort_direction)
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
def sort_icon_classes
|
|
@@ -112,6 +112,14 @@ module BetterUi
|
|
|
112
112
|
end
|
|
113
113
|
end
|
|
114
114
|
|
|
115
|
+
def sort_link?
|
|
116
|
+
@sortable && @sort_url.present?
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def sort_link_html
|
|
120
|
+
@sort_html
|
|
121
|
+
end
|
|
122
|
+
|
|
115
123
|
def validate_align(align)
|
|
116
124
|
unless ALIGNMENTS.include?(align)
|
|
117
125
|
raise ArgumentError, "Invalid align: #{align}. Must be one of: #{ALIGNMENTS.join(', ')}"
|
|
@@ -16,10 +16,15 @@
|
|
|
16
16
|
<tr>
|
|
17
17
|
<% columns.each do |column| %>
|
|
18
18
|
<th class="<%= collection_header_cell_classes(column) %>" scope="col">
|
|
19
|
-
<% if column.sortable %>
|
|
19
|
+
<% if column.sortable && collection_sort_link?(column) %>
|
|
20
|
+
<%= link_to collection_sort_url(column), **collection_sort_link_html(column), class: "flex items-center gap-1 no-underline text-inherit" do %>
|
|
21
|
+
<%= column.display_label %>
|
|
22
|
+
<span class="<%= collection_sort_icon_classes(column) %>"><%= raw collection_sort_icon(column) %></span>
|
|
23
|
+
<% end %>
|
|
24
|
+
<% elsif column.sortable %>
|
|
20
25
|
<span class="flex items-center gap-1">
|
|
21
26
|
<%= column.display_label %>
|
|
22
|
-
<span class="<%= collection_sort_icon_classes(column) %>"><%= collection_sort_icon(column) %></span>
|
|
27
|
+
<span class="<%= collection_sort_icon_classes(column) %>"><%= raw collection_sort_icon(column) %></span>
|
|
23
28
|
</span>
|
|
24
29
|
<% else %>
|
|
25
30
|
<%= column.display_label %>
|
|
@@ -30,6 +30,7 @@ module BetterUi
|
|
|
30
30
|
# <% t.with_column(key: :role, label: "Role") { |user| user.role.humanize } %>
|
|
31
31
|
# <% end %>
|
|
32
32
|
class TableComponent < ApplicationComponent
|
|
33
|
+
include Concerns::SortIcons
|
|
33
34
|
SIZES = {
|
|
34
35
|
xs: { th_padding: "px-2 py-1.5", td_padding: "px-2 py-2", text: "text-xs" },
|
|
35
36
|
sm: { th_padding: "px-3 py-2", td_padding: "px-3 py-2.5", text: "text-sm" },
|
|
@@ -93,6 +94,10 @@ module BetterUi
|
|
|
93
94
|
body_row_partial: nil,
|
|
94
95
|
header_partial: nil,
|
|
95
96
|
footer_partial: nil,
|
|
97
|
+
sort_column: nil,
|
|
98
|
+
sort_direction: nil,
|
|
99
|
+
sort_url: nil,
|
|
100
|
+
sort_html: {},
|
|
96
101
|
container_classes: nil,
|
|
97
102
|
table_classes: nil,
|
|
98
103
|
header_classes: nil,
|
|
@@ -115,6 +120,10 @@ module BetterUi
|
|
|
115
120
|
@body_row_partial = body_row_partial
|
|
116
121
|
@header_partial = header_partial
|
|
117
122
|
@footer_partial = footer_partial
|
|
123
|
+
@sort_column = sort_column&.to_sym
|
|
124
|
+
@table_sort_direction = sort_direction&.to_sym
|
|
125
|
+
@sort_url = sort_url
|
|
126
|
+
@sort_html = sort_html || {}
|
|
118
127
|
@container_classes = container_classes
|
|
119
128
|
@table_classes = table_classes
|
|
120
129
|
@header_classes = header_classes
|
|
@@ -417,20 +426,41 @@ module BetterUi
|
|
|
417
426
|
"cursor-pointer select-none"
|
|
418
427
|
end
|
|
419
428
|
|
|
420
|
-
# Collection mode:
|
|
429
|
+
# Collection mode: whether this column is currently sorted
|
|
430
|
+
# Table-level sort_column overrides column-level sorted
|
|
431
|
+
def effective_sorted?(column)
|
|
432
|
+
if @sort_column
|
|
433
|
+
column.key && column.key.to_sym == @sort_column
|
|
434
|
+
else
|
|
435
|
+
column.sorted
|
|
436
|
+
end
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
# Collection mode: effective sort direction for a column
|
|
440
|
+
# Table-level overrides column-level when the column is the sorted one
|
|
441
|
+
def effective_sort_direction(column)
|
|
442
|
+
if @sort_column && effective_sorted?(column) && @table_sort_direction
|
|
443
|
+
@table_sort_direction
|
|
444
|
+
else
|
|
445
|
+
column.sort_direction
|
|
446
|
+
end
|
|
447
|
+
end
|
|
448
|
+
|
|
449
|
+
# Collection mode: next sort direction (toggles asc↔desc)
|
|
450
|
+
def next_sort_direction(column)
|
|
451
|
+
effective_sorted?(column) && effective_sort_direction(column) == :asc ? :desc : :asc
|
|
452
|
+
end
|
|
453
|
+
|
|
454
|
+
# Collection mode: sort icon SVG
|
|
421
455
|
def collection_sort_icon(column)
|
|
422
456
|
return nil unless column.sortable
|
|
423
|
-
return "↕" unless column.sorted
|
|
424
457
|
|
|
425
|
-
|
|
426
|
-
when :asc then "↑"
|
|
427
|
-
when :desc then "↓"
|
|
428
|
-
end
|
|
458
|
+
sort_icon_svg(sorted: effective_sorted?(column), direction: effective_sort_direction(column))
|
|
429
459
|
end
|
|
430
460
|
|
|
431
461
|
# Collection mode: sort icon classes
|
|
432
462
|
def collection_sort_icon_classes(column)
|
|
433
|
-
return "text-grayscale-400" unless column
|
|
463
|
+
return "text-grayscale-400" unless effective_sorted?(column)
|
|
434
464
|
|
|
435
465
|
case @variant
|
|
436
466
|
when :primary then "text-primary-700"
|
|
@@ -445,6 +475,28 @@ module BetterUi
|
|
|
445
475
|
end
|
|
446
476
|
end
|
|
447
477
|
|
|
478
|
+
# Collection mode: whether a column should render a sort link
|
|
479
|
+
def collection_sort_link?(column)
|
|
480
|
+
return false unless column.sortable
|
|
481
|
+
column.sort_url.present? || @sort_url.present?
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
# Collection mode: resolved sort URL for a column
|
|
485
|
+
def collection_sort_url(column)
|
|
486
|
+
if column.sort_url.present?
|
|
487
|
+
column.sort_url
|
|
488
|
+
elsif @sort_url.present?
|
|
489
|
+
@sort_url.call(column.key, next_sort_direction(column))
|
|
490
|
+
end
|
|
491
|
+
end
|
|
492
|
+
|
|
493
|
+
# Collection mode: merged sort link HTML attributes
|
|
494
|
+
def collection_sort_link_html(column)
|
|
495
|
+
base = @sort_html.dup
|
|
496
|
+
override = column.sort_html
|
|
497
|
+
base.merge(override)
|
|
498
|
+
end
|
|
499
|
+
|
|
448
500
|
# Partial helpers
|
|
449
501
|
def body_row_partial?
|
|
450
502
|
@body_row_partial.present?
|
data/lib/better_ui/version.rb
CHANGED
data/spec/components/previews/better_ui/table/table_component_preview/collection_mode.html.erb
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
<%
|
|
2
2
|
users = [
|
|
3
|
-
OpenStruct.new(name: "Alice Johnson", email: "alice@example.com", role: "admin", active: true),
|
|
4
|
-
OpenStruct.new(name: "Bob Smith", email: "bob@example.com", role: "editor", active: true),
|
|
5
|
-
OpenStruct.new(name: "Charlie Brown", email: "charlie@example.com", role: "viewer", active: false),
|
|
6
|
-
OpenStruct.new(name: "Diana Prince", email: "diana@example.com", role: "admin", active: true)
|
|
3
|
+
::OpenStruct.new(name: "Alice Johnson", email: "alice@example.com", role: "admin", active: true),
|
|
4
|
+
::OpenStruct.new(name: "Bob Smith", email: "bob@example.com", role: "editor", active: true),
|
|
5
|
+
::OpenStruct.new(name: "Charlie Brown", email: "charlie@example.com", role: "viewer", active: false),
|
|
6
|
+
::OpenStruct.new(name: "Diana Prince", email: "diana@example.com", role: "admin", active: true)
|
|
7
7
|
]
|
|
8
8
|
%>
|
|
9
9
|
|
|
@@ -44,10 +44,10 @@
|
|
|
44
44
|
|
|
45
45
|
<%
|
|
46
46
|
orders = [
|
|
47
|
-
OpenStruct.new(number: "ORD-001", customer: "Alice Johnson", status: "Shipped", total: "$299.00", pending: false),
|
|
48
|
-
OpenStruct.new(number: "ORD-002", customer: "Bob Smith", status: "Pending Review", total: "$149.50", pending: true),
|
|
49
|
-
OpenStruct.new(number: "ORD-003", customer: "Charlie Brown", status: "Delivered", total: "$75.25", pending: false),
|
|
50
|
-
OpenStruct.new(number: "ORD-004", customer: "Diana Prince", status: "Pending Review", total: "$512.00", pending: true)
|
|
47
|
+
::OpenStruct.new(number: "ORD-001", customer: "Alice Johnson", status: "Shipped", total: "$299.00", pending: false),
|
|
48
|
+
::OpenStruct.new(number: "ORD-002", customer: "Bob Smith", status: "Pending Review", total: "$149.50", pending: true),
|
|
49
|
+
::OpenStruct.new(number: "ORD-003", customer: "Charlie Brown", status: "Delivered", total: "$75.25", pending: false),
|
|
50
|
+
::OpenStruct.new(number: "ORD-004", customer: "Diana Prince", status: "Pending Review", total: "$512.00", pending: true)
|
|
51
51
|
]
|
|
52
52
|
%>
|
|
53
53
|
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
<%
|
|
6
6
|
users = [
|
|
7
|
-
OpenStruct.new(id: 1, name: "Alice Johnson", email: "alice@example.com", role: "Admin"),
|
|
8
|
-
OpenStruct.new(id: 2, name: "Bob Smith", email: "bob@example.com", role: "Editor"),
|
|
9
|
-
OpenStruct.new(id: 3, name: "Charlie Brown", email: "charlie@example.com", role: "Viewer")
|
|
7
|
+
::OpenStruct.new(id: 1, name: "Alice Johnson", email: "alice@example.com", role: "Admin"),
|
|
8
|
+
::OpenStruct.new(id: 2, name: "Bob Smith", email: "bob@example.com", role: "Editor"),
|
|
9
|
+
::OpenStruct.new(id: 3, name: "Charlie Brown", email: "charlie@example.com", role: "Viewer")
|
|
10
10
|
]
|
|
11
11
|
%>
|
|
12
12
|
|
|
@@ -29,9 +29,9 @@
|
|
|
29
29
|
|
|
30
30
|
<%
|
|
31
31
|
users = [
|
|
32
|
-
OpenStruct.new(name: "Alice Johnson", email: "alice@example.com", role: "Admin", joined: "2024-01-15"),
|
|
33
|
-
OpenStruct.new(name: "Bob Smith", email: "bob@example.com", role: "Editor", joined: "2024-02-20"),
|
|
34
|
-
OpenStruct.new(name: "Charlie Brown", email: "charlie@example.com", role: "Viewer", joined: "2024-03-10")
|
|
32
|
+
::OpenStruct.new(name: "Alice Johnson", email: "alice@example.com", role: "Admin", joined: "2024-01-15"),
|
|
33
|
+
::OpenStruct.new(name: "Bob Smith", email: "bob@example.com", role: "Editor", joined: "2024-02-20"),
|
|
34
|
+
::OpenStruct.new(name: "Charlie Brown", email: "charlie@example.com", role: "Viewer", joined: "2024-03-10")
|
|
35
35
|
]
|
|
36
36
|
%>
|
|
37
37
|
|
|
@@ -41,4 +41,46 @@
|
|
|
41
41
|
<% t.with_column(key: :role, label: "Role") %>
|
|
42
42
|
<% t.with_column(key: :joined, label: "Joined", sortable: true, sorted: true, sort_direction: :desc) %>
|
|
43
43
|
<% end %>
|
|
44
|
+
|
|
45
|
+
<h2 class="text-xl font-bold mb-4 mt-8">Sortable with Links (Slot Mode)</h2>
|
|
46
|
+
<p class="text-sm text-grayscale-500 mb-4">Sort headers wrapped in clickable links with sort_url.</p>
|
|
47
|
+
|
|
48
|
+
<%= render BetterUi::Table::TableComponent.new(variant: :success) do |t| %>
|
|
49
|
+
<% t.with_header do |h| %>
|
|
50
|
+
<% h.with_cell(label: "Name", sortable: true, sorted: true, sort_direction: :asc,
|
|
51
|
+
sort_url: "?sort=name&direction=desc",
|
|
52
|
+
sort_html: { data: { turbo_frame: "_top" } }) %>
|
|
53
|
+
<% h.with_cell(label: "Email", sortable: true,
|
|
54
|
+
sort_url: "?sort=email&direction=asc") %>
|
|
55
|
+
<% h.with_cell(label: "Role") %>
|
|
56
|
+
<% end %>
|
|
57
|
+
|
|
58
|
+
<% [
|
|
59
|
+
["Alice Johnson", "alice@example.com", "Admin"],
|
|
60
|
+
["Bob Smith", "bob@example.com", "Editor"]
|
|
61
|
+
].each do |row_data| %>
|
|
62
|
+
<% t.with_row do |r| %>
|
|
63
|
+
<% r.with_cell { row_data[0] } %>
|
|
64
|
+
<% r.with_cell { row_data[1] } %>
|
|
65
|
+
<% r.with_cell { row_data[2] } %>
|
|
66
|
+
<% end %>
|
|
67
|
+
<% end %>
|
|
68
|
+
<% end %>
|
|
69
|
+
|
|
70
|
+
<h2 class="text-xl font-bold mb-4 mt-8">Sortable with Links (Collection Mode + Table-level sort_url)</h2>
|
|
71
|
+
<p class="text-sm text-grayscale-500 mb-4">Table-level sort_url auto-generates links for all sortable columns, with sort_column deriving the sorted state.</p>
|
|
72
|
+
|
|
73
|
+
<%= render BetterUi::Table::TableComponent.new(
|
|
74
|
+
collection: users,
|
|
75
|
+
variant: :accent,
|
|
76
|
+
sort_column: :name,
|
|
77
|
+
sort_direction: :asc,
|
|
78
|
+
sort_url: ->(key, dir) { "?sort=#{key}&direction=#{dir}" },
|
|
79
|
+
sort_html: { data: { turbo_frame: "_top" } }
|
|
80
|
+
) do |t| %>
|
|
81
|
+
<% t.with_column(key: :name, label: "Name", sortable: true) %>
|
|
82
|
+
<% t.with_column(key: :email, label: "Email", sortable: true) %>
|
|
83
|
+
<% t.with_column(key: :role, label: "Role") %>
|
|
84
|
+
<% t.with_column(key: :joined, label: "Joined", sortable: true) %>
|
|
85
|
+
<% end %>
|
|
44
86
|
</div>
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: better_ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.11.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Umberto Peserico
|
|
@@ -158,6 +158,7 @@ files:
|
|
|
158
158
|
- app/components/better_ui/table/cell_component.rb
|
|
159
159
|
- app/components/better_ui/table/cell_component/cell_component.html.erb
|
|
160
160
|
- app/components/better_ui/table/column_component.rb
|
|
161
|
+
- app/components/better_ui/table/concerns/sort_icons.rb
|
|
161
162
|
- app/components/better_ui/table/header_cell_component.rb
|
|
162
163
|
- app/components/better_ui/table/header_cell_component/header_cell_component.html.erb
|
|
163
164
|
- app/components/better_ui/table/header_component.rb
|