keystone_ui 0.14.0 → 0.15.1
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/assets/javascripts/keystone_ui/index.js +2 -0
- data/app/assets/javascripts/keystone_ui/page_theme.js +13 -0
- data/app/components/keystone/ui/bucket_component.rb +8 -2
- data/app/components/keystone/ui/form_field_component.html.erb +1 -1
- data/app/components/keystone/ui/form_field_component.rb +6 -1
- data/config/importmap.rb +1 -0
- data/lib/keystone_ui/version.rb +1 -1
- data/the_local/agents/keystone_ui-develop.md +26 -6
- data/the_local/agents/keystone_ui-info.md +11 -3
- data/the_local/agents/keystone_ui-install.md +11 -2
- data/the_local/interface.yml +4 -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: 60fbc4a896b71babee643443b4583435ffa85d0b1be67324afdc901169807f68
|
|
4
|
+
data.tar.gz: e83753c421f5e7095b552fc39776c982c823273665bd10dee5f5a769df39c204
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 56fb8e5421b4cb2e9669af2dec0a452ee7c58f316b10f63ce6ea0096ecfd347fbaf01708613a23a00365c9d0e88d7576fbd46c83e13509d5ff9f823f22e9c688
|
|
7
|
+
data.tar.gz: 70375887467d685ddf82dc96074ec99d3ce43694ad53bf022d315083478e9f21238099528924e133d9bdb425410d8727a8873c8db8119531843fa39a3eb97106
|
|
@@ -13,6 +13,7 @@ import StatCardInfoController from "keystone_ui/stat_card_info_controller"
|
|
|
13
13
|
import AutoSubmitController from "keystone_ui/auto_submit_controller"
|
|
14
14
|
import LineChartController from "keystone_ui/line_chart_controller"
|
|
15
15
|
import ThemeToggleController from "keystone_ui/theme_toggle_controller"
|
|
16
|
+
import { keepPageThemeInStep } from "keystone_ui/page_theme"
|
|
16
17
|
|
|
17
18
|
export function registerControllers(application) {
|
|
18
19
|
application.register("color-picker", ColorPickerController)
|
|
@@ -30,6 +31,7 @@ export function registerControllers(application) {
|
|
|
30
31
|
application.register("auto-submit", AutoSubmitController)
|
|
31
32
|
application.register("line-chart", LineChartController)
|
|
32
33
|
application.register("theme-toggle", ThemeToggleController)
|
|
34
|
+
keepPageThemeInStep()
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export { ColorPickerController, MultiSelectController, SwipeDeckController, ColumnPickerController, FileUploadController, DropdownController, DismissController, ModalController, ClipboardController, TabSwitcherController, AccordionController, StatCardInfoController, AutoSubmitController, LineChartController }
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function keepPageThemeInStep(page = document) {
|
|
2
|
+
page.addEventListener("turbo:before-render", ({ detail }) => {
|
|
3
|
+
const next = detail.newBody.closest("html")
|
|
4
|
+
if (!next) return
|
|
5
|
+
|
|
6
|
+
const theme = next.dataset.theme
|
|
7
|
+
if (theme) {
|
|
8
|
+
page.documentElement.dataset.theme = theme
|
|
9
|
+
} else {
|
|
10
|
+
delete page.documentElement.dataset.theme
|
|
11
|
+
}
|
|
12
|
+
})
|
|
13
|
+
}
|
|
@@ -19,8 +19,8 @@ module Keystone
|
|
|
19
19
|
attr_reader :goal, :actual, :label
|
|
20
20
|
|
|
21
21
|
def initialize(goal:, actual:, label: nil, over: :success)
|
|
22
|
-
@goal = goal
|
|
23
|
-
@actual = actual
|
|
22
|
+
@goal = number(:goal, goal)
|
|
23
|
+
@actual = number(:actual, actual)
|
|
24
24
|
@label = label
|
|
25
25
|
@over_fill_classes = OVER_GOAL_FILL_CLASSES.fetch(over)
|
|
26
26
|
end
|
|
@@ -65,6 +65,12 @@ module Keystone
|
|
|
65
65
|
|
|
66
66
|
private
|
|
67
67
|
|
|
68
|
+
def number(name, value)
|
|
69
|
+
return value if value.is_a?(Numeric)
|
|
70
|
+
|
|
71
|
+
raise ArgumentError, "#{name} must be a number, got #{value.inspect}"
|
|
72
|
+
end
|
|
73
|
+
|
|
68
74
|
def fill_color_classes
|
|
69
75
|
return @over_fill_classes if actual > goal
|
|
70
76
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<textarea name="<%= @attribute %>" rows="3" class="<%= Keystone::Ui::TextareaComponent::BASE_CLASSES %>"<% if @placeholder %> placeholder="<%= @placeholder %>"<% end %>><%= @value %></textarea>
|
|
16
16
|
<% elsif select? %>
|
|
17
17
|
<select name="<%= @attribute %>" class="<%= Keystone::Ui::SelectComponent::BASE_CLASSES %>">
|
|
18
|
-
<% unless required? %><option value=""
|
|
18
|
+
<% unless required? %><option value=""><%= blank_option_text %></option><% end %>
|
|
19
19
|
<% select_options.each do |label, value| %>
|
|
20
20
|
<option value="<%= value %>" <%= "selected" if @value.to_s == value.to_s %>><%= label %></option>
|
|
21
21
|
<% end %>
|
|
@@ -11,7 +11,7 @@ module Keystone
|
|
|
11
11
|
CHECKBOX_CLASSES = "ks-checkbox"
|
|
12
12
|
CHECKBOX_WRAPPER_CLASSES = "flex items-center gap-2"
|
|
13
13
|
|
|
14
|
-
def initialize(attribute:, label: nil, type: :text, required: false, hint: nil, placeholder: nil, min: nil, max: nil, step: nil, value: nil, options: [], errors: [])
|
|
14
|
+
def initialize(attribute:, label: nil, type: :text, required: false, hint: nil, placeholder: nil, min: nil, max: nil, step: nil, value: nil, options: [], errors: [], include_blank: nil)
|
|
15
15
|
@attribute = attribute
|
|
16
16
|
@label = label
|
|
17
17
|
@type = type
|
|
@@ -24,6 +24,7 @@ module Keystone
|
|
|
24
24
|
@value = value
|
|
25
25
|
@options = options
|
|
26
26
|
@errors = Array(errors)
|
|
27
|
+
@include_blank = include_blank.to_s
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def label_text
|
|
@@ -66,6 +67,10 @@ module Keystone
|
|
|
66
67
|
@options
|
|
67
68
|
end
|
|
68
69
|
|
|
70
|
+
def blank_option_text
|
|
71
|
+
@include_blank
|
|
72
|
+
end
|
|
73
|
+
|
|
69
74
|
def input_options
|
|
70
75
|
options = { name: @attribute.to_s, class: Keystone::Ui::InputComponent::BASE_CLASSES }
|
|
71
76
|
unless textarea?
|
data/config/importmap.rb
CHANGED
|
@@ -14,6 +14,7 @@ pin "keystone_ui/stat_card_info_controller", to: "keystone_ui/stat_card_info_con
|
|
|
14
14
|
pin "keystone_ui/auto_submit_controller", to: "keystone_ui/auto_submit_controller.js"
|
|
15
15
|
pin "keystone_ui/line_chart_controller", to: "keystone_ui/line_chart_controller.js"
|
|
16
16
|
pin "keystone_ui/theme_toggle_controller", to: "keystone_ui/theme_toggle_controller.js"
|
|
17
|
+
pin "keystone_ui/page_theme", to: "keystone_ui/page_theme.js"
|
|
17
18
|
|
|
18
19
|
# Chart.js for the line-chart controller, so host apps don't pin it themselves.
|
|
19
20
|
# Vendored as a single self-contained bundle (deps inlined, no external imports).
|
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, dashboards, charts, marketing sections — 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, dashboards, charts, 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
|
---
|
|
@@ -89,6 +89,12 @@ outer element. See Conventions before using it.
|
|
|
89
89
|
- `ui_mobile_actions` — no keywords, takes a block. An ellipsis dropdown for
|
|
90
90
|
mobile actions; the block holds the menu items. Hidden above `lg:`.
|
|
91
91
|
- `ui_settings_link(label:, href:)` — a full-width settings row with a chevron.
|
|
92
|
+
- `ui_theme_toggle` — no keywords, no block. A row of three buttons, Light, Dark
|
|
93
|
+
and System, that switches the page's theme at once and remembers the choice in
|
|
94
|
+
the `keystone_theme` cookie for a year. System follows the operating system.
|
|
95
|
+
The button for the page's current mode renders pressed. When the current mode
|
|
96
|
+
is a custom palette supplied by another gem, no button is pressed, because the
|
|
97
|
+
toggle does not offer custom.
|
|
92
98
|
|
|
93
99
|
### Forms
|
|
94
100
|
|
|
@@ -96,7 +102,7 @@ outer element. See Conventions before using it.
|
|
|
96
102
|
The `<form>` wrapper. `method:` may be `:patch`/`:put`/`:delete` and is
|
|
97
103
|
translated for Rails. Set `multipart: true` when the form contains a file
|
|
98
104
|
upload.
|
|
99
|
-
- `ui_form_field(attribute:, label: nil, type: :text, required: false, hint: nil, placeholder: nil, min: nil, max: nil, step: nil, value: nil, options: [], errors: [])`
|
|
105
|
+
- `ui_form_field(attribute:, label: nil, type: :text, required: false, hint: nil, placeholder: nil, min: nil, max: nil, step: nil, value: nil, options: [], errors: [], include_blank: nil)`
|
|
100
106
|
— a labeled field with hint and error text. This is the default way to render
|
|
101
107
|
an input. `type:` `:text` `:number` `:email` `:password` `:date` `:textarea`
|
|
102
108
|
`:checkbox` `:select`. `attribute:` is used verbatim as the input's `name`, so
|
|
@@ -104,7 +110,9 @@ outer element. See Conventions before using it.
|
|
|
104
110
|
pass `label:` whenever the attribute is a nested name. `label:` defaults to the
|
|
105
111
|
attribute with underscores turned to spaces and the first letter capitalized.
|
|
106
112
|
`options:` is for `:select` and takes `[[label, value], ...]`; `value:` picks
|
|
107
|
-
the selected option, and a non-required select gets a leading
|
|
113
|
+
the selected option, and a non-required select gets a leading empty option,
|
|
114
|
+
worded by `include_blank:` (for example `"Not set yet"`) or left blank without
|
|
115
|
+
it. Never add your own empty choice to `options:` as well. A
|
|
108
116
|
`:checkbox` renders its label beside the box, submits `"0"` when unchecked and
|
|
109
117
|
`"1"` when checked, and pre-checks when `value:` is `"1"`. `errors:` is an
|
|
110
118
|
array of message strings.
|
|
@@ -229,8 +237,12 @@ outer element. See Conventions before using it.
|
|
|
229
237
|
- `ui_bucket(goal:, actual:, label: nil, over: :success)` — an upright container
|
|
230
238
|
for one target, filled from the bottom toward `goal:`. It shows the optional
|
|
231
239
|
`label` on top, then `goal`, the container, `actual`, and the percent reached.
|
|
232
|
-
`goal` and `actual`
|
|
233
|
-
|
|
240
|
+
`goal` and `actual` must be numbers: a string such as `"9,000"`, or `nil`,
|
|
241
|
+
raises `ArgumentError` at render time. They are printed as Ruby prints them,
|
|
242
|
+
with no thousands separators, so `9000` shows as `9000` and `9000.0` as
|
|
243
|
+
`9000.0`. A value read from a decimal column is a `BigDecimal`, which prints
|
|
244
|
+
as `0.9e4`, so convert it with `to_i` or `to_f` first. The percent is
|
|
245
|
+
`actual / goal * 100` rounded and **not**
|
|
234
246
|
clamped (so 150% shows as 150%), and it is 0 when `goal` is zero. The fill
|
|
235
247
|
stops at the top once the goal is reached. Within the goal the fill uses the
|
|
236
248
|
accent colour; over it the fill turns green with `over: :success` or amber with
|
|
@@ -301,7 +313,15 @@ outer element. See Conventions before using it.
|
|
|
301
313
|
routes or a persistence strategy — put the choice to the developer, then
|
|
302
314
|
implement what they pick.
|
|
303
315
|
|
|
304
|
-
8.
|
|
316
|
+
8. To let users pick light or dark, place `ui_theme_toggle`. Where it goes — a
|
|
317
|
+
settings screen, the navbar's `desktop_right` or a mobile menu — is the
|
|
318
|
+
developer's choice, so ask before placing it. It only stays correct across
|
|
319
|
+
page loads and Turbo visits when the app's layout already writes the theme
|
|
320
|
+
onto its `html` tag and the gem's Stimulus controllers are registered. If the
|
|
321
|
+
layout's `<html` tag carries nothing for the theme, stop and hand that part to
|
|
322
|
+
`keystone_ui-install`.
|
|
323
|
+
|
|
324
|
+
9. Read back what you wrote and delete every Tailwind class and inline `style`
|
|
305
325
|
you added. If the result still needs one, that is a signal the wrong helper
|
|
306
326
|
was chosen — go back to step 5. Bring it to the developer only if no helper
|
|
307
327
|
fits.
|
|
@@ -47,8 +47,9 @@ holds the catalog.
|
|
|
47
47
|
|
|
48
48
|
## Conventions
|
|
49
49
|
|
|
50
|
-
- **Helpers, not classes.** Every
|
|
51
|
-
called from ERB.
|
|
50
|
+
- **Helpers, not classes.** Every piece of UI is a view helper prefixed `ui_`,
|
|
51
|
+
called from ERB. The one layout helper that is not prefixed `ui_` writes the
|
|
52
|
+
theme onto the page's `html` tag, and it belongs to the install local. Components live under the `Keystone::Ui` namespace, but a
|
|
52
53
|
host app does not name a component class directly. The one exception is the
|
|
53
54
|
table column value object, which is passed as an argument and renders nothing.
|
|
54
55
|
- **Containers take blocks, leaves take keywords.** Helpers that wrap content
|
|
@@ -63,6 +64,9 @@ holds the catalog.
|
|
|
63
64
|
different symbols, and the develop local carries the real values. Most
|
|
64
65
|
components raise on a symbol they do not know, so a wrong guess fails at
|
|
65
66
|
render time.
|
|
67
|
+
- **Figures are numbers.** Components that measure or compare values, such as
|
|
68
|
+
progress bars, funnels and buckets, do arithmetic on them. Pass a number, not
|
|
69
|
+
a formatted string such as `"9,000"`. A bucket raises on one.
|
|
66
70
|
- **Semantic color, not literal color.** The themed hue is `accent-*` and the
|
|
67
71
|
themed neutral family is `surface-*`, both CSS custom properties whose
|
|
68
72
|
defaults (blue and zinc) come from the keystone_ui-styles gem. Retheming an
|
|
@@ -75,7 +79,11 @@ holds the catalog.
|
|
|
75
79
|
cookie, then a mode another gem supplies, then light. System leaves the page
|
|
76
80
|
to follow the operating system. Custom marks the page for a palette another
|
|
77
81
|
gem defines. The theme toggle does not offer it, so a page reaches it when
|
|
78
|
-
another gem supplies it.
|
|
82
|
+
another gem supplies it. On a Turbo visit, the page being shown sets the
|
|
83
|
+
theme, so a change to the mode on the server shows up without a full reload.
|
|
84
|
+
Marking the layout with the theme is set up through
|
|
85
|
+
the install local, and placing the toggle on a screen goes through the develop
|
|
86
|
+
local.
|
|
79
87
|
- **Tailwind classes are static strings.** Class names are never interpolated,
|
|
80
88
|
so Tailwind's scanner can find them. Widths and heights that depend on data,
|
|
81
89
|
such as a progress bar or a bucket's fill, are set with an inline style
|
|
@@ -24,6 +24,11 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
24
24
|
custom mode),
|
|
25
25
|
and the `tailwind_imports` and `tailwind_sources` lists (extra CSS files and
|
|
26
26
|
scan paths added to the Tailwind build).
|
|
27
|
+
- `keystone_theme_attributes` — a layout helper placed inside the `<html>` tag.
|
|
28
|
+
It writes `data-theme="light"`, `data-theme="dark"` or `data-theme="custom"`
|
|
29
|
+
for the page's mode, and writes nothing for system so the page follows the
|
|
30
|
+
operating system. The mode is the `keystone_theme` cookie's choice, then the
|
|
31
|
+
configured `theme_mode_supplier`, then light.
|
|
27
32
|
|
|
28
33
|
## How to use it
|
|
29
34
|
|
|
@@ -61,8 +66,9 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
61
66
|
`import { registerControllers } from "keystone_ui/index"` and
|
|
62
67
|
`registerControllers(application)`.
|
|
63
68
|
- `app/views/layouts/application.html.erb` — adds
|
|
64
|
-
`<%= keystone_theme_attributes %>`
|
|
65
|
-
|
|
69
|
+
`<%= keystone_theme_attributes %>` directly after the first `<html` in the
|
|
70
|
+
file, so the tag reads `<html <%= keystone_theme_attributes %> ...>`. A
|
|
71
|
+
layout that already contains the call is left unchanged.
|
|
66
72
|
|
|
67
73
|
Read its output for two warnings:
|
|
68
74
|
|
|
@@ -70,6 +76,9 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
70
76
|
the Stimulus application is set up and add those two lines there. Without
|
|
71
77
|
them, dropdowns, modals, file uploads, the column picker, the theme toggle
|
|
72
78
|
and the other interactive components do nothing.
|
|
79
|
+
`registerControllers(application)` also copies `data-theme` from each page
|
|
80
|
+
Turbo renders onto the `<html>` tag. Without it, a Turbo visit keeps the
|
|
81
|
+
theme of the first page loaded.
|
|
73
82
|
- `app/views/layouts/application.html.erb not found` — ask the developer which
|
|
74
83
|
layout the app renders and add `<%= keystone_theme_attributes %>` to its
|
|
75
84
|
`<html>` tag. Without it, a saved light or dark choice is not applied when
|
data/the_local/interface.yml
CHANGED
|
@@ -3,6 +3,7 @@ scope: UI — pages, forms, tables, navigation, dashboards
|
|
|
3
3
|
install:
|
|
4
4
|
- bin/rails generate keystone:install
|
|
5
5
|
- KeystoneUi.configure
|
|
6
|
+
- keystone_theme_attributes
|
|
6
7
|
|
|
7
8
|
develop:
|
|
8
9
|
- ui_accordion
|
|
@@ -56,11 +57,13 @@ develop:
|
|
|
56
57
|
- ui_pipeline
|
|
57
58
|
- ui_code
|
|
58
59
|
- ui_disclosure
|
|
60
|
+
- ui_theme_toggle
|
|
59
61
|
- Keystone::Ui::Column
|
|
60
62
|
|
|
61
63
|
sources:
|
|
62
64
|
- lib/generators/keystone/install_generator.rb
|
|
63
65
|
- lib/keystone_ui/configuration.rb
|
|
66
|
+
- lib/keystone_ui/theme_choice.rb
|
|
64
67
|
- app/helpers/keystone_ui_helper.rb
|
|
65
68
|
- app/components/keystone/ui/accordion_component.rb
|
|
66
69
|
- app/components/keystone/ui/alert_component.rb
|
|
@@ -105,6 +108,7 @@ sources:
|
|
|
105
108
|
- app/components/keystone/ui/page_header_component.rb
|
|
106
109
|
- app/components/keystone/ui/panel_component.rb
|
|
107
110
|
- app/components/keystone/ui/pipeline_component.rb
|
|
111
|
+
- app/components/keystone/ui/theme_toggle_component.rb
|
|
108
112
|
- app/components/keystone/ui/progress_component.rb
|
|
109
113
|
- app/components/keystone/ui/radio_card_component.rb
|
|
110
114
|
- app/components/keystone/ui/section_component.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.15.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tyler Schneider
|
|
@@ -64,6 +64,7 @@ files:
|
|
|
64
64
|
- app/assets/javascripts/keystone_ui/line_chart_controller.js
|
|
65
65
|
- app/assets/javascripts/keystone_ui/modal_controller.js
|
|
66
66
|
- app/assets/javascripts/keystone_ui/multi_select_controller.js
|
|
67
|
+
- app/assets/javascripts/keystone_ui/page_theme.js
|
|
67
68
|
- app/assets/javascripts/keystone_ui/stat_card_info_controller.js
|
|
68
69
|
- app/assets/javascripts/keystone_ui/swipe_deck_controller.js
|
|
69
70
|
- app/assets/javascripts/keystone_ui/tab_switcher_controller.js
|