keystone_ui 0.31.0 → 0.33.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/keystone/ui/data_table_component.html.erb +3 -0
- data/app/components/keystone/ui/data_table_component.rb +28 -6
- data/app/components/keystone/ui/figure_component.html.erb +1 -0
- data/app/components/keystone/ui/figure_component.rb +24 -0
- data/app/components/keystone/ui/info_component.html.erb +1 -1
- data/app/components/keystone/ui/info_component.rb +6 -0
- data/app/helpers/keystone_ui_helper.rb +4 -0
- data/lib/keystone_ui/configuration.rb +5 -1
- data/lib/keystone_ui/safelist.rb +1 -0
- data/lib/keystone_ui/version.rb +1 -1
- data/the_local/agents/keystone_ui-develop.md +42 -6
- data/the_local/agents/keystone_ui-info.md +26 -5
- data/the_local/agents/keystone_ui-install.md +24 -3
- data/the_local/interface.yml +2 -0
- metadata +3 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 599c6b4269b4ca049a5aefe106cb71dc6205554c49fb6e72824f25cc3b6f2597
|
|
4
|
+
data.tar.gz: 390d82ea8082927248351ba74796fde3a05afe4994b151c79169e0cb190ecacd
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2b44fd40afcc3d275dab96ab0401f2748a5555d5e38eb319af16d998454e30f094d9e799603658b0597b7a0e8688a9a8d864aa2e170c3b750d5351a37db123d5
|
|
7
|
+
data.tar.gz: 65064fb15715bcebbe95efadb89b2a395d06889b6d4962467faeac520df18f88083acd7f5d23ffe8c6057f9434916906861a4c3f02515ae4306cf545bf9eba23
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
<% if column_picker %>
|
|
2
|
+
<%= render column_picker %>
|
|
3
|
+
<% end %>
|
|
1
4
|
<div class="<%= Keystone::Ui::DataTableComponent::WRAPPER_CLASSES %>">
|
|
2
5
|
<table class="relative min-w-full divide-y divide-gray-300 dark:divide-white/15">
|
|
3
6
|
<thead class="<%= Keystone::Ui::DataTableComponent::HEAD_CLASSES %>">
|
|
@@ -6,10 +6,10 @@ module Keystone
|
|
|
6
6
|
EMPTY_CELL_CLASSES = "ks-table-cell-middle text-sm"
|
|
7
7
|
BODY_CLASSES = "ks-table-body"
|
|
8
8
|
HEAD_CLASSES = "ks-table-head"
|
|
9
|
-
WRAPPER_CLASSES = "ks-table overflow-
|
|
9
|
+
WRAPPER_CLASSES = "ks-table overflow-x-auto"
|
|
10
10
|
HEADER_CLASSES_FIRST = "ks-table-header ks-table-header-first text-left text-sm"
|
|
11
11
|
HEADER_CLASSES_MIDDLE = "ks-table-header ks-table-header-middle text-left text-sm"
|
|
12
|
-
HEADER_CLASSES_LAST = "ks-table-header-last"
|
|
12
|
+
HEADER_CLASSES_LAST = "ks-table-header ks-table-header-last text-right text-sm"
|
|
13
13
|
|
|
14
14
|
ROW_CLASSES_FIRST = "ks-table-cell-first text-sm whitespace-nowrap"
|
|
15
15
|
ROW_CLASSES_MIDDLE = "ks-table-cell-middle text-sm whitespace-nowrap"
|
|
@@ -26,11 +26,12 @@ module Keystone
|
|
|
26
26
|
SORT_DESC_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 3a.75.75 0 0 1 .75.75v10.638l3.96-4.158a.75.75 0 1 1 1.08 1.04l-5.25 5.5a.75.75 0 0 1-1.08 0l-5.25-5.5a.75.75 0 0 1 1.08-1.04l3.96 4.158V3.75A.75.75 0 0 1 10 3Z" clip-rule="evenodd" /></svg>'
|
|
27
27
|
SORT_NEUTRAL_ICON = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M10 3a.75.75 0 0 1 .55.24l3.25 3.5a.75.75 0 1 1-1.1 1.02L10 4.852 7.3 7.76a.75.75 0 0 1-1.1-1.02l3.25-3.5A.75.75 0 0 1 10 3Zm-3.76 9.2a.75.75 0 0 1 1.06.04l2.7 2.908 2.7-2.908a.75.75 0 1 1 1.1 1.02l-3.25 3.5a.75.75 0 0 1-1.1 0l-3.25-3.5a.75.75 0 0 1 .04-1.06Z" clip-rule="evenodd" /></svg>'
|
|
28
28
|
|
|
29
|
-
def initialize(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [])
|
|
29
|
+
def initialize(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [], key: nil)
|
|
30
30
|
@items = items.to_a
|
|
31
|
-
all_columns = columns.map { |col| normalize_column(col) }
|
|
32
|
-
|
|
33
|
-
@columns =
|
|
31
|
+
@all_columns = columns.map { |col| normalize_column(col) }
|
|
32
|
+
@hidden_columns = hidden_columns
|
|
33
|
+
@columns = visible_columns(hidden_columns)
|
|
34
|
+
@key = key
|
|
34
35
|
@empty_message = empty_message
|
|
35
36
|
@sort = sort&.to_sym
|
|
36
37
|
@sort_direction = sort_direction&.to_sym
|
|
@@ -41,6 +42,7 @@ module Keystone
|
|
|
41
42
|
|
|
42
43
|
def before_render
|
|
43
44
|
content
|
|
45
|
+
apply_saved_layout if @key
|
|
44
46
|
end
|
|
45
47
|
|
|
46
48
|
def link(column_key, &block)
|
|
@@ -55,6 +57,12 @@ module Keystone
|
|
|
55
57
|
!!@actions_block
|
|
56
58
|
end
|
|
57
59
|
|
|
60
|
+
def column_picker
|
|
61
|
+
return unless @save_url
|
|
62
|
+
|
|
63
|
+
@column_picker ||= ColumnPickerComponent.new(columns: @all_columns, hidden_columns: @hidden_columns, save_url: @save_url)
|
|
64
|
+
end
|
|
65
|
+
|
|
58
66
|
def column_keys
|
|
59
67
|
@column_keys ||= @columns.map(&:key)
|
|
60
68
|
end
|
|
@@ -134,6 +142,20 @@ module Keystone
|
|
|
134
142
|
|
|
135
143
|
private
|
|
136
144
|
|
|
145
|
+
def apply_saved_layout
|
|
146
|
+
saved = KeystoneUi.configuration.supplied_preference(helpers, @key)
|
|
147
|
+
return unless saved
|
|
148
|
+
|
|
149
|
+
@hidden_columns = saved[:value]["hidden_columns"]
|
|
150
|
+
@columns = visible_columns(@hidden_columns)
|
|
151
|
+
@save_url = saved[:save_url]
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def visible_columns(hidden_columns)
|
|
155
|
+
hidden_keys = Array(hidden_columns).map(&:to_sym).to_set
|
|
156
|
+
@all_columns.reject { |col| col.hideable? && hidden_keys.include?(col.key) }
|
|
157
|
+
end
|
|
158
|
+
|
|
137
159
|
def visual_column_count
|
|
138
160
|
@columns.length + (actions? ? 1 : 0)
|
|
139
161
|
end
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<span class="<%= classes %>"><%= text %></span>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Keystone
|
|
4
|
+
module Ui
|
|
5
|
+
class FigureComponent < ViewComponent::Base
|
|
6
|
+
TONES = {
|
|
7
|
+
neutral: nil,
|
|
8
|
+
success: "ks-tone-success",
|
|
9
|
+
danger: "ks-tone-danger"
|
|
10
|
+
}.freeze
|
|
11
|
+
|
|
12
|
+
def initialize(text:, tone: :neutral)
|
|
13
|
+
@text = text
|
|
14
|
+
@tone = tone
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
attr_reader :text
|
|
18
|
+
|
|
19
|
+
def classes
|
|
20
|
+
[ "ks-figure", TONES.fetch(@tone) ].compact.join(" ")
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
<span class="
|
|
1
|
+
<span class="<%= wrapper_classes %>" data-controller="info" data-action="click@window->info#hide scroll@window->info#close">
|
|
2
2
|
<button type="button" class="<%= button_classes %>" data-info-target="button" data-action="mouseenter->info#peek mouseleave->info#unpeek click->info#toggle" aria-label="More about this"><%= icon.html_safe %></button>
|
|
3
3
|
<span class="<%= summary_classes %>" data-info-target="summary"><%= summary %></span>
|
|
4
4
|
<% if content? %>
|
|
@@ -229,6 +229,10 @@ module KeystoneUiHelper
|
|
|
229
229
|
render Keystone::Ui::CalculationComponent.new(**args)
|
|
230
230
|
end
|
|
231
231
|
|
|
232
|
+
def ui_figure(**args)
|
|
233
|
+
render Keystone::Ui::FigureComponent.new(**args)
|
|
234
|
+
end
|
|
235
|
+
|
|
232
236
|
def ui_info(**args, &block)
|
|
233
237
|
render(Keystone::Ui::InfoComponent.new(**args), &block)
|
|
234
238
|
end
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module KeystoneUi
|
|
4
4
|
class Configuration
|
|
5
|
-
attr_accessor :accent, :surface, :theme_mode_supplier, :look_supplier, :trail_supplier
|
|
5
|
+
attr_accessor :accent, :surface, :theme_mode_supplier, :look_supplier, :trail_supplier, :preference_supplier
|
|
6
6
|
attr_reader :tailwind_imports, :tailwind_sources, :looks, :default_look
|
|
7
7
|
|
|
8
8
|
def initialize
|
|
@@ -33,6 +33,10 @@ module KeystoneUi
|
|
|
33
33
|
def supplied_trail(view)
|
|
34
34
|
trail_supplier&.call(view)
|
|
35
35
|
end
|
|
36
|
+
|
|
37
|
+
def supplied_preference(view, key)
|
|
38
|
+
preference_supplier&.call(view, key)
|
|
39
|
+
end
|
|
36
40
|
end
|
|
37
41
|
|
|
38
42
|
def self.configuration
|
data/lib/keystone_ui/safelist.rb
CHANGED
data/lib/keystone_ui/version.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: keystone_ui-develop
|
|
3
|
-
description: Use PROACTIVELY for building or editing screens in a Rails app that has Keystone UI — pages, forms, tables, navigation, action menus for a record's Edit and Delete, dashboards, charts, marketing sections, a light/dark theme switch — MUST BE USED instead of hand-writing ERB and Tailwind for UI.
|
|
3
|
+
description: Use PROACTIVELY for building or editing screens in a Rails app that has Keystone UI — pages, forms, tables, navigation, action menus for a record's Edit and Delete, dashboards, charts, amounts shown in green or red as a gain or loss, marketing sections, a light/dark theme switch — MUST BE USED instead of hand-writing ERB and Tailwind for UI.
|
|
4
4
|
tools: Read, Write, Edit, Grep
|
|
5
5
|
scope: UI — pages, forms, tables, navigation, dashboards
|
|
6
6
|
---
|
|
@@ -207,19 +207,29 @@ outer element. See Conventions before using it.
|
|
|
207
207
|
|
|
208
208
|
### Tables
|
|
209
209
|
|
|
210
|
-
- `ui_data_table(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [])`
|
|
210
|
+
- `ui_data_table(items:, columns:, empty_message: nil, sort: nil, sort_direction: nil, sort_url: nil, hidden_columns: [], key: nil)`
|
|
211
211
|
— takes a block yielding the table. `items:` are records or hashes; each cell
|
|
212
212
|
value is read by calling the column key on the item, falling back to `item[key]`.
|
|
213
213
|
`columns:` accepts plain `{ key: "Label" }` hashes or `Keystone::Ui::Column`
|
|
214
214
|
objects. In the block, `table.link(:column_key) { |item| url }` turns that
|
|
215
215
|
column's cells into links and `table.actions { |item| ... }` appends a
|
|
216
|
-
right-aligned actions column.
|
|
216
|
+
right-aligned actions column. With no actions column, the last data
|
|
217
|
+
column's header and cells are both right-aligned, so put the column of
|
|
218
|
+
amounts last to line them up under their header. Each row's actions render inside an action
|
|
217
219
|
menu, so the `actions` block holds `ui_action_menu_item` calls and nothing
|
|
218
220
|
else, never buttons or bare links. Sorting requires all three of `sort:` (the
|
|
219
221
|
current column key), `sort_direction:` (`:asc`/`:desc`), and `sort_url:` (a
|
|
220
222
|
lambda taking `(column_key, direction)` and returning a URL); headers then
|
|
221
223
|
render as links that flip direction. `hidden_columns:` drops columns
|
|
222
|
-
server-side and only affects columns declared `hideable: true`.
|
|
224
|
+
server-side and only affects columns declared `hideable: true`. `key:` (a
|
|
225
|
+
symbol or string) names the table so it looks up a saved layout through the
|
|
226
|
+
app's preference supplier. When the supplier returns a saved value for the
|
|
227
|
+
key, the hideable columns listed under its `"hidden_columns"` replace the
|
|
228
|
+
ones passed in `hidden_columns:`, and when it also returns a save address the
|
|
229
|
+
table renders a "Columns" menu above itself that saves to it. When the
|
|
230
|
+
supplier returns nothing, when no supplier is set, or when no `key:` is
|
|
231
|
+
passed, the table renders from `hidden_columns:` with no Columns menu, so
|
|
232
|
+
`hidden_columns:` is the table's default layout.
|
|
223
233
|
- `Keystone::Ui::Column.new(key, header_text, mobile_hidden: false, sortable: false, hideable: false)`
|
|
224
234
|
— a column with per-column options, for when a `{ key: "Label" }` hash is not
|
|
225
235
|
enough. `mobile_hidden:` hides the column below `sm:`; `sortable:` opts it into
|
|
@@ -228,7 +238,9 @@ outer element. See Conventions before using it.
|
|
|
228
238
|
dropdown of checkboxes for every `hideable` column. Pass it the same columns
|
|
229
239
|
and hidden keys as the table. On toggle it sends `PATCH save_url` with JSON
|
|
230
240
|
`{ "hidden_columns": ["key", ...] }` and a `X-CSRF-Token` header, then reloads
|
|
231
|
-
the page. The app must provide that endpoint and persist the list.
|
|
241
|
+
the page. The app must provide that endpoint and persist the list. A table
|
|
242
|
+
given `key:` renders its own Columns menu when the supplier gives a save
|
|
243
|
+
address, so never add `ui_column_picker` beside such a table.
|
|
232
244
|
|
|
233
245
|
### Content and status
|
|
234
246
|
|
|
@@ -238,6 +250,13 @@ outer element. See Conventions before using it.
|
|
|
238
250
|
only to the button form.
|
|
239
251
|
- `ui_badge(label:, variant: :neutral, class: nil)` — a pill. `variant:`
|
|
240
252
|
`:neutral` `:success` `:danger` `:warning` `:info`.
|
|
253
|
+
- `ui_figure(text:, tone: :neutral)` — no block. One figure, such as an amount,
|
|
254
|
+
as inline text with no pill or box around it. `tone:` `:neutral` prints it in
|
|
255
|
+
the surrounding text colour, `:success` in green and `:danger` in red; any
|
|
256
|
+
other symbol raises `KeyError`. `text:` is printed as given, so format
|
|
257
|
+
numbers, currency and any minus sign before passing it. Its output can be
|
|
258
|
+
passed anywhere a string is shown, such as a `ui_data_table` cell value or
|
|
259
|
+
column label.
|
|
241
260
|
- `ui_alert(message:, type: :info, title: nil, dismissible: false, class: nil)` —
|
|
242
261
|
a banner.
|
|
243
262
|
`type:` `:info` `:success` `:warning` `:error`. `dismissible: true` adds a
|
|
@@ -270,7 +289,8 @@ outer element. See Conventions before using it.
|
|
|
270
289
|
numbers and currency before passing them. Place it directly under the figure
|
|
271
290
|
it explains, such as a `ui_stat_card`.
|
|
272
291
|
- `ui_info(summary:)` — an info button, named "More about this" for screen
|
|
273
|
-
readers, placed inline beside the thing it explains
|
|
292
|
+
readers, placed inline beside the thing it explains, and sits level with the
|
|
293
|
+
middle of the text beside it. `summary:` is a short
|
|
274
294
|
line of text shown in a floating panel while the button is hovered. The block
|
|
275
295
|
is optional and holds the full detail. With a block, tapping or clicking the
|
|
276
296
|
button toggles a second floating panel holding the block's content, and the
|
|
@@ -453,6 +473,13 @@ outer element. See Conventions before using it.
|
|
|
453
473
|
text with no columns and no separate total, the app's keystone_ui-styles
|
|
454
474
|
version does not define the `ks-breakdown` classes, so stop and hand that
|
|
455
475
|
part to `keystone_ui-install` as well, and add no classes to fix it.
|
|
476
|
+
To show an amount as a gain or a loss, use `ui_figure` with `tone:` rather
|
|
477
|
+
than a `ui_badge` or a colour class. Which amounts are coloured, and whether
|
|
478
|
+
a value counts as a gain or a loss, is the app's own rule, so ask the
|
|
479
|
+
developer rather than pick. If a figure with `:success` or `:danger` shows in
|
|
480
|
+
the plain text colour, the app's keystone_ui-styles version does not define
|
|
481
|
+
the `ks-figure` and `ks-tone-*` classes, so stop and hand that part to
|
|
482
|
+
`keystone_ui-install`, and add no classes to fix it.
|
|
456
483
|
A field whose value must be one of a fixed list is a `:select` with
|
|
457
484
|
`options:`, and a field that accepts any text and offers common values is a
|
|
458
485
|
text field with `suggestions:`. Which one a field is, and which values it
|
|
@@ -485,6 +512,15 @@ outer element. See Conventions before using it.
|
|
|
485
512
|
objects as soon as one column needs `mobile_hidden:`, `sortable:`, or
|
|
486
513
|
`hideable:`.
|
|
487
514
|
|
|
515
|
+
For a table whose hideable columns a user should be able to choose and keep,
|
|
516
|
+
check whether the app's Keystone UI initializer sets a
|
|
517
|
+
`preference_supplier`. If it does, pass `key:` and the default
|
|
518
|
+
`hidden_columns:`, and add no `ui_column_picker`. Which key names the table
|
|
519
|
+
and which columns it hides by default are the developer's choice, so ask
|
|
520
|
+
rather than pick. If the app sets no supplier, either use `ui_column_picker`
|
|
521
|
+
with an endpoint the app owns, as in step 7, or hand setting up a supplier to
|
|
522
|
+
`keystone_ui-install`, and ask the developer which.
|
|
523
|
+
|
|
488
524
|
7. Wire up anything that posts back. Several helpers render controls whose
|
|
489
525
|
endpoints the app must own — the column picker's save URL, the pipeline's box
|
|
490
526
|
and link URLs, the swipe deck's outcome events, the modal's open trigger, the
|
|
@@ -15,7 +15,7 @@ library of view helpers built on ViewComponent. Screens are built from named
|
|
|
15
15
|
pieces — page shells, sections, panels, grids, form fields, data tables,
|
|
16
16
|
navigation bars, breadcrumbs, cards, stat tiles, charts, funnels, goal buckets, pipelines,
|
|
17
17
|
banners, the calculation behind a figure, a breakdown of amounts and their
|
|
18
|
-
total, an info button — instead of hand-written ERB and
|
|
18
|
+
total, a figure coloured as a gain or a loss, an info button — instead of hand-written ERB and
|
|
19
19
|
Tailwind. Every class the UI renders lives inside the gem, in frozen constants,
|
|
20
20
|
so the look is defined in one place.
|
|
21
21
|
|
|
@@ -47,7 +47,8 @@ shell also uses the page container.
|
|
|
47
47
|
This local declares no commands. The two working surfaces belong elsewhere:
|
|
48
48
|
|
|
49
49
|
- **Getting the gem into a host app** — adding it, wiring Tailwind, Stimulus and
|
|
50
|
-
the theme attributes on the layout, setting the palette
|
|
50
|
+
the theme attributes on the layout, setting the palette, and the suppliers
|
|
51
|
+
for trails, themes, looks and saved table layouts → **`keystone_ui-install`**.
|
|
51
52
|
- **Building UI with it** — which helper renders what, what keywords it takes,
|
|
52
53
|
how helpers nest → **`keystone_ui-develop`**.
|
|
53
54
|
|
|
@@ -88,7 +89,8 @@ holds the catalog.
|
|
|
88
89
|
extra text about themselves. Given that text, the piece shows an info button,
|
|
89
90
|
and the text stays hidden until the button is hovered or tapped. A piece
|
|
90
91
|
given no such text shows no button. On a radio card and a checkbox row the
|
|
91
|
-
button sits on the line with the label.
|
|
92
|
+
button sits on the line with the label. Wherever it is placed, the button
|
|
93
|
+
sits level with the text beside it.
|
|
92
94
|
- **Standalone info button.** The same info button can be placed on its own,
|
|
93
95
|
beside anything. It takes a short summary, which is required, and shows it
|
|
94
96
|
when the button is hovered. Given nothing more, a tap shows the summary too.
|
|
@@ -113,6 +115,25 @@ holds the catalog.
|
|
|
113
115
|
of its own, so a breakdown looks right only with a keystone_ui-styles version
|
|
114
116
|
that defines those classes. It has no button and no hidden state of
|
|
115
117
|
its own, and it can be placed inside an info button's detail.
|
|
118
|
+
- **A toned figure is text.** A figure shows one amount inline, in plain text
|
|
119
|
+
or in the success or danger colour, so it reads as a gain or a loss without a
|
|
120
|
+
badge around it. The amount is passed as already-formatted text and shown as
|
|
121
|
+
written, and the tone is chosen by name. An unknown tone raises at render
|
|
122
|
+
time. The colours come from keystone_ui-styles, so a figure shows its tone
|
|
123
|
+
only with a keystone_ui-styles version that defines those classes.
|
|
124
|
+
- **The last table column is right-aligned.** In a data table with no actions
|
|
125
|
+
column, the last column's header is right-aligned like the cells beneath it,
|
|
126
|
+
so a figure or total placed in that header lines up with the figures below.
|
|
127
|
+
- **Saved table layouts.** A data table can be given a key naming it. A table
|
|
128
|
+
with a key asks the app, or another gem such as keystone_ui-preferences, for
|
|
129
|
+
the layout saved under that key for the request. A saved layout lists the
|
|
130
|
+
columns to hide, and only columns marked hideable can be hidden. When a
|
|
131
|
+
layout is saved, it replaces the columns the table hides by default. When
|
|
132
|
+
nothing is saved, the table hides the columns its own call names, so those
|
|
133
|
+
are its default layout. When the supplier also gives an address to save to,
|
|
134
|
+
a "Columns" menu appears above the table and saves the user's choice there.
|
|
135
|
+
A table with no key, or an app with no supplier, renders from its own call
|
|
136
|
+
alone. Setting up the supplier belongs to the install local.
|
|
116
137
|
- **Suggestions.** A form field can carry a list of suggested values. The
|
|
117
138
|
browser offers them while the field's text is typed, and the user can still
|
|
118
139
|
enter a value that is not on the list. This applies to a field with a typed
|
|
@@ -126,7 +147,7 @@ holds the catalog.
|
|
|
126
147
|
different symbols, and the develop local carries the real values. Most
|
|
127
148
|
components raise on a symbol they do not know, so a wrong guess fails at
|
|
128
149
|
render time.
|
|
129
|
-
- **
|
|
150
|
+
- **Measured values are numbers.** Components that measure or compare values, such as
|
|
130
151
|
progress bars, funnels and buckets, do arithmetic on them. Pass a number, not
|
|
131
152
|
a formatted string such as `"9,000"`. A bucket raises on one.
|
|
132
153
|
- **A funnel has two shapes.** Both size each step against the first step and
|
|
@@ -198,5 +219,5 @@ holds the catalog.
|
|
|
198
219
|
and the theme toggle ship with the gem as Stimulus controllers registered once
|
|
199
220
|
at install. A host writes no JavaScript to use them. Components that post
|
|
200
221
|
somewhere, such as the column picker and the pipeline, post to endpoints the
|
|
201
|
-
host app owns.
|
|
222
|
+
host app or another gem owns.
|
|
202
223
|
- Ruby >= 3.2. ViewComponent >= 2.0 and < 5.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: keystone_ui-install
|
|
3
|
-
description: Use to hook Keystone UI into a project — adding the gem, running the install generator to wire Tailwind, the Stimulus controllers and the layout's theme attributes, and configuring the palette, the theme mode supplier, registered looks, the breadcrumb trail supplier and extra Tailwind imports and sources.
|
|
3
|
+
description: Use to hook Keystone UI into a project — adding the gem, running the install generator to wire Tailwind, the Stimulus controllers and the layout's theme attributes, and configuring the palette, the theme mode supplier, registered looks, the breadcrumb trail supplier, the saved table layout supplier and extra Tailwind imports and sources.
|
|
4
4
|
tools: Bash, Read, Edit
|
|
5
5
|
scope: UI — pages, forms, tables, navigation, dashboards
|
|
6
6
|
---
|
|
@@ -26,6 +26,8 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
26
26
|
`look_supplier` (which registered look a page gets),
|
|
27
27
|
`trail_supplier` (a callable that supplies the breadcrumb trail for form and
|
|
28
28
|
show pages that pass none, and their Back link when they pass none either),
|
|
29
|
+
`preference_supplier` (a callable that supplies the saved column layout of a
|
|
30
|
+
data table given a `key:`, and the address its Columns menu saves to),
|
|
29
31
|
and the `tailwind_imports` and `tailwind_sources` lists (extra CSS files and
|
|
30
32
|
scan paths added to the Tailwind build).
|
|
31
33
|
- `keystone_theme_attributes` — a layout helper placed inside the `<html>` tag.
|
|
@@ -40,7 +42,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
40
42
|
## How to use it
|
|
41
43
|
|
|
42
44
|
1. Confirm the prerequisites: Ruby >= 3.2 and **tailwindcss-rails v4+** in the
|
|
43
|
-
host app. The gem brings ViewComponent and keystone_ui-styles 0.
|
|
45
|
+
host app. The gem brings ViewComponent and keystone_ui-styles 0.10.0 or later with it.
|
|
44
46
|
Tailwind does not have to be initialized first, because the generator creates
|
|
45
47
|
the stylesheet if it is missing.
|
|
46
48
|
|
|
@@ -153,7 +155,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
153
155
|
checkbox row, radio card, option card, file upload and colour picker read
|
|
154
156
|
these variables. So do the data display components: stat card, chart card,
|
|
155
157
|
card link, CTA banner, feature grid, hero, data table, code, accordion,
|
|
156
|
-
disclosure, calculation, info button, breakdown, tab switcher, progress,
|
|
158
|
+
disclosure, calculation, info button, breakdown, figure, tab switcher, progress,
|
|
157
159
|
funnel, bucket, pipeline and swipe deck.
|
|
158
160
|
So do the navigation components: navbar, nav item, nav dropdown, bottom nav,
|
|
159
161
|
mobile header and settings link. The desktop "Back" link and the breadcrumbs
|
|
@@ -179,6 +181,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
179
181
|
config.default_look = :compact
|
|
180
182
|
config.look_supplier = ->(view) { view.current_user&.look }
|
|
181
183
|
config.trail_supplier = ->(view) { view.breadcrumb_trail }
|
|
184
|
+
config.preference_supplier = ->(view, key) { TablePreferences.for(view.current_user, key) }
|
|
182
185
|
config.tailwind_imports << "/absolute/path/to/extra.css"
|
|
183
186
|
config.tailwind_sources << "/absolute/path/to/components/**/*.{erb,rb}"
|
|
184
187
|
end
|
|
@@ -229,6 +232,24 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
229
232
|
writing the callable. If some form or show pages pass no `back_url:`, ask
|
|
230
233
|
where their Back link should come from before enabling the supplier or
|
|
231
234
|
leaving it out.
|
|
235
|
+
- `preference_supplier` — a callable that receives the view and a data
|
|
236
|
+
table's key and returns `{ value:, save_url: }`, or `nil` when nothing is
|
|
237
|
+
saved for that key. It is asked only for tables rendered with a `key:`. A
|
|
238
|
+
table with no `key:`, a supplier returning `nil`, or no supplier at all
|
|
239
|
+
renders with the hidden columns its own call passes.
|
|
240
|
+
- `value` must hold the hidden column names under the string key
|
|
241
|
+
`"hidden_columns"`, such as `{ "hidden_columns" => ["sku"] }`. A symbol key
|
|
242
|
+
is not read, and the table then hides no columns. Only columns marked
|
|
243
|
+
hideable are hidden.
|
|
244
|
+
- When `save_url` is present, the table shows a Columns menu above itself.
|
|
245
|
+
Toggling a column sends a `PATCH` to `save_url` with the JSON body
|
|
246
|
+
`{"hidden_columns": [...]}` and the page's CSRF token, then reloads the
|
|
247
|
+
page. The host must have a route and action at that address that store the
|
|
248
|
+
list for that key. With no `save_url`, the saved layout applies and no menu
|
|
249
|
+
is shown.
|
|
250
|
+
- A companion preferences gem may set this supplier for the app. Ask the
|
|
251
|
+
developer whether the app uses one, or which code stores each user's table
|
|
252
|
+
layouts, before writing the callable.
|
|
232
253
|
- `tailwind_imports` and `tailwind_sources` — lists to append to, never
|
|
233
254
|
assign. Each import becomes an `@import` line and each source becomes an
|
|
234
255
|
`@source` line in `keystone_source.css` on the next boot. They are for
|
data/the_local/interface.yml
CHANGED
|
@@ -62,11 +62,13 @@ develop:
|
|
|
62
62
|
- ui_disclosure
|
|
63
63
|
- ui_calculation
|
|
64
64
|
- ui_info
|
|
65
|
+
- ui_figure
|
|
65
66
|
- ui_breakdown
|
|
66
67
|
- ui_theme_toggle
|
|
67
68
|
- Keystone::Ui::Column
|
|
68
69
|
|
|
69
70
|
sources:
|
|
71
|
+
- app/components/keystone/ui/figure_component.rb
|
|
70
72
|
- lib/generators/keystone/install_generator.rb
|
|
71
73
|
- lib/keystone_ui/configuration.rb
|
|
72
74
|
- lib/keystone_ui/missing_back_link.rb
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: keystone_ui
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.33.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tyler Schneider
|
|
@@ -125,6 +125,8 @@ files:
|
|
|
125
125
|
- app/components/keystone/ui/disclosure_component.rb
|
|
126
126
|
- app/components/keystone/ui/feature_grid_component.html.erb
|
|
127
127
|
- app/components/keystone/ui/feature_grid_component.rb
|
|
128
|
+
- app/components/keystone/ui/figure_component.html.erb
|
|
129
|
+
- app/components/keystone/ui/figure_component.rb
|
|
128
130
|
- app/components/keystone/ui/file_upload_component.html.erb
|
|
129
131
|
- app/components/keystone/ui/file_upload_component.rb
|
|
130
132
|
- app/components/keystone/ui/form_component.html.erb
|