keystone_ui 0.21.0 → 0.22.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3ebe6bbc917891684b563a1981daf0cc0b32a747143f52d72af17bd2a9df2e7d
4
- data.tar.gz: 0320fdf4a5c56b52e6919641022b1fbd05dd2ccdcb5c8b91553f696d3ab3e115
3
+ metadata.gz: 59407e58c161eccb32c1dd76581bb7c0e8ea6f5005fe5f9bde9b061860ffe2ef
4
+ data.tar.gz: 4cf237c4e194ecb2c509765191546f633ceb3f0be82563c1eeedcb9f8fb24b06
5
5
  SHA512:
6
- metadata.gz: b6b75345f8165d8ae02e9d7a7e6fe24a015f37f07437082dcad6d3543fa17b56013073ef9c69729be5b330b1959f69e0bb33d628df176d01fe69ae296c33713a
7
- data.tar.gz: 04b8b2e35b0d24fcb507d0293142aba61723ed1737478da8376bce4b6533b97fe12ca2efe9a629c92916b1aba4fdee8f47ec7bbf85c8e74bb39e60d409ae9375
6
+ metadata.gz: 97139bc519bef9a218073c10d290ef335df3471fa294b392298bd4c613490baf173ab02fbd2e4395c2c2c7aba563127d19754049d6f808db8f42b8d0aebfd61b
7
+ data.tar.gz: 6371eaa8e6bd1a00b028f2820026e0a12c21f3e959a436de04e17ef0b288fb73513948a88c944c2be18a514a7ef54eaa624a87eee4a5dfdc7030b5202c9cd338
@@ -3,14 +3,16 @@
3
3
  <% content_for :form_page_back_url, @back_url %>
4
4
 
5
5
  <% if @trail %>
6
- <%= render Keystone::Ui::BreadcrumbsComponent.new(trail: @trail, current: @title) %>
6
+ <% content_for :keystone_page_header, render(Keystone::Ui::BreadcrumbsComponent.new(trail: @trail, current: @title)) %>
7
7
  <% else %>
8
- <%= render Keystone::Ui::DesktopBackLinkComponent.new(url: @back_url) %>
8
+ <% content_for :keystone_page_header, render(Keystone::Ui::DesktopBackLinkComponent.new(url: @back_url)) %>
9
9
  <% end %>
10
10
 
11
- <div class="<%= DESKTOP_WRAPPER_CLASSES %>">
12
- <h1 class="<%= TITLE_CLASSES %>"><%= @title %></h1>
13
- <% if subtitle? %>
14
- <p class="<%= SUBTITLE_CLASSES %>"><%= @subtitle %></p>
15
- <% end %>
16
- </div>
11
+ <% content_for :keystone_page_header do %>
12
+ <div class="<%= DESKTOP_WRAPPER_CLASSES %>">
13
+ <h1 class="<%= TITLE_CLASSES %>"><%= @title %></h1>
14
+ <% if subtitle? %>
15
+ <p class="<%= SUBTITLE_CLASSES %>"><%= @subtitle %></p>
16
+ <% end %>
17
+ </div>
18
+ <% end %>
@@ -7,13 +7,18 @@ module Keystone
7
7
  TITLE_CLASSES = "ks-page-title text-2xl"
8
8
  SUBTITLE_CLASSES = "ks-page-header-subtitle text-sm"
9
9
 
10
- def initialize(title:, back_url:, subtitle: nil, trail: nil)
10
+ def initialize(title:, back_url: nil, subtitle: nil, trail: nil)
11
11
  @title = title
12
12
  @back_url = back_url
13
13
  @subtitle = subtitle
14
14
  @trail = trail
15
15
  end
16
16
 
17
+ def before_render
18
+ @trail ||= KeystoneUi.configuration.supplied_trail(helpers)
19
+ @back_url ||= @trail&.last&.last
20
+ end
21
+
17
22
  def subtitle?
18
23
  !@subtitle.nil?
19
24
  end
@@ -1,3 +1,4 @@
1
1
  <div class="<%= classes %>">
2
+ <%= content_for(:keystone_page_header) %>
2
3
  <%= content %>
3
4
  </div>
@@ -4,7 +4,7 @@
4
4
  <% content_for :show_page_subtitle, @subtitle if @subtitle.present? %>
5
5
 
6
6
  <% if @trail %>
7
- <%= render Keystone::Ui::BreadcrumbsComponent.new(trail: @trail, current: @title) %>
7
+ <% content_for :keystone_page_header, render(Keystone::Ui::BreadcrumbsComponent.new(trail: @trail, current: @title)) %>
8
8
  <% else %>
9
- <%= render Keystone::Ui::DesktopBackLinkComponent.new(url: @back_url) %>
9
+ <% content_for :keystone_page_header, render(Keystone::Ui::DesktopBackLinkComponent.new(url: @back_url)) %>
10
10
  <% end %>
@@ -7,13 +7,18 @@ module Keystone
7
7
  TITLE_CLASSES = "ks-page-title text-2xl"
8
8
  SUBTITLE_CLASSES = "ks-page-header-subtitle text-sm"
9
9
 
10
- def initialize(title:, back_url:, subtitle: nil, trail: nil)
10
+ def initialize(title:, back_url: nil, subtitle: nil, trail: nil)
11
11
  @title = title
12
12
  @back_url = back_url
13
13
  @subtitle = subtitle
14
14
  @trail = trail
15
15
  end
16
16
 
17
+ def before_render
18
+ @trail ||= KeystoneUi.configuration.supplied_trail(helpers)
19
+ @back_url ||= @trail&.last&.last
20
+ end
21
+
17
22
  def subtitle?
18
23
  !@subtitle.nil?
19
24
  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
5
+ attr_accessor :accent, :surface, :theme_mode_supplier, :look_supplier, :trail_supplier
6
6
  attr_reader :tailwind_imports, :tailwind_sources, :looks, :default_look
7
7
 
8
8
  def initialize
@@ -29,6 +29,10 @@ module KeystoneUi
29
29
  def supplied_theme_mode(view)
30
30
  theme_mode_supplier&.call(view)
31
31
  end
32
+
33
+ def supplied_trail(view)
34
+ trail_supplier&.call(view)
35
+ end
32
36
  end
33
37
 
34
38
  def self.configuration
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KeystoneUi
4
- VERSION = "0.21.0"
4
+ VERSION = "0.22.0"
5
5
  end
@@ -42,7 +42,9 @@ outer element. See Conventions before using it.
42
42
  - `ui_page(max_width: :full, padding: :standard, top_offset: nil, class: nil)` —
43
43
  takes a block. The outer wrapper for a screen. `max_width:` `:sm` `:md` `:lg`
44
44
  `:xl` `:full`; `padding:` `:standard` or `:none`; `top_offset:` `:sm` `:md`
45
- `:lg` `:xl` to clear a fixed navbar.
45
+ `:lg` `:xl` to clear a fixed navbar. When `ui_form_page` or `ui_show_page` was
46
+ called earlier on the same screen, `ui_page` renders their back link or
47
+ breadcrumbs, and the form page's title, at its top, above the block.
46
48
  - `ui_section(title: nil, subtitle: nil, action: nil, spacing: :md, class: nil)`
47
49
  — takes a block. A titled block of content with an optional right-aligned
48
50
  link. `action:` is `{ label:, href: }`; `spacing:` `:sm` `:md` `:lg`.
@@ -62,18 +64,28 @@ outer element. See Conventions before using it.
62
64
  `sm:`). Call `header.action { ... }` in the block to place a custom control on
63
65
  the right; only what `action` receives is rendered. Passing `action_url:`
64
66
  publishes that URL and label for a mobile navbar to pick up.
65
- - `ui_form_page(title:, back_url:, subtitle: nil, trail: nil)` — the shell
66
- marker for a form screen. Renders a "Back" link to `back_url` shown from `lg:`
67
- up, then the title and subtitle shown from `md:` up, and publishes the title
68
- and back URL so the navbar can render mobile header context. Passing `trail:`
69
- replaces the "Back" link with breadcrumbs: the trail's links followed by
70
- `title` unlinked, as `ui_breadcrumbs` renders them. `back_url:` is still
71
- required with a trail, because the mobile header still uses it.
72
- - `ui_show_page(title:, back_url:, subtitle: nil, trail: nil)` — the shell marker
73
- for a detail screen. Renders a "Back" link to `back_url` shown from `lg:` up,
74
- and publishes the title, subtitle, and back URL for the navbar. It renders no
75
- title, so pair it with `ui_page_header` for the desktop title. `trail:` works
76
- as it does on `ui_form_page`, ending the breadcrumbs with `title` unlinked.
67
+ - `ui_form_page(title:, back_url: nil, subtitle: nil, trail: nil)` — the shell
68
+ marker for a form screen. It renders nothing where it is called. It publishes
69
+ the title and back URL so the navbar can render mobile header context, and
70
+ hands `ui_page` a "Back" link to `back_url` shown from `lg:` up, then the
71
+ title and subtitle shown from `md:` up. Call it before `ui_page`, outside
72
+ `ui_page`'s block, or none of that appears. Passing `trail:` replaces the
73
+ "Back" link with breadcrumbs: the trail's links followed by `title` unlinked,
74
+ as `ui_breadcrumbs` renders them. With no `trail:`, it uses the trail the app
75
+ supplies for the current request, if the app supplies one. With no
76
+ `back_url:`, the back URL is the `href` of the trail's last link. A `trail:`
77
+ or `back_url:` passed here always wins over the supplied ones. With no
78
+ `back_url:` and no trail from either place, the "Back" link and the mobile
79
+ header point at the current page, so pass one.
80
+ - `ui_show_page(title:, back_url: nil, subtitle: nil, trail: nil)` — the shell
81
+ marker for a detail screen. It renders nothing where it is called. It
82
+ publishes the title, subtitle, and back URL for the navbar, and hands
83
+ `ui_page` a "Back" link to `back_url` shown from `lg:` up. Call it before
84
+ `ui_page`, outside `ui_page`'s block. It shows no title, so put
85
+ `ui_page_header` inside the `ui_page` block for the desktop title. `trail:`
86
+ and `back_url:` work as they do on `ui_form_page`, including the supplied
87
+ trail and the fallback to the trail's last link, and the breadcrumbs end with
88
+ `title` unlinked.
77
89
  - `ui_breadcrumbs(trail:, current: nil)` — a line of links shown only from `lg:`
78
90
  up. `trail:` is `[[label, href], ...]`, from the top level down, and each pair
79
91
  renders as a link, separated by `›`. `current:` is the page being shown,
@@ -300,14 +312,33 @@ outer element. See Conventions before using it.
300
312
  composition before inventing one; that screen is the house style.
301
313
 
302
314
  3. Pick the page shell for what you are building:
303
- - a form screen → `ui_form_page`
304
- - a detail screen → `ui_show_page`
315
+ - a form screen → `ui_form_page`, then `ui_page` holding the form
316
+ - a detail screen → `ui_show_page`, then `ui_page` holding `ui_page_header`
317
+ and the details
305
318
  - anything else → `ui_page`, with `ui_page_header` for the desktop title.
306
319
 
307
- `ui_form_page` and `ui_show_page` render the desktop "Back" link themselves,
308
- so never add a second back link or button to those screens. Whether a screen
320
+ ```erb
321
+ <%= ui_form_page(title: "New quote", back_url: quotes_path) %>
322
+ <%= ui_page(max_width: :md) do %>
323
+ <%= ui_form(action: quotes_path) do %>
324
+ ...
325
+ <% end %>
326
+ <% end %>
327
+ ```
328
+
329
+ The shell call always comes first and sits outside `ui_page`'s block,
330
+ because `ui_page` renders what the shell handed it at its own top. A form or
331
+ detail screen without `ui_page` shows no desktop "Back" link or form title.
332
+ Those shells supply the desktop "Back" link themselves, so never add a
333
+ second back link or button to those screens. Whether a screen
309
334
  shows that "Back" link or breadcrumbs, and which parent screens the trail
310
- names, is the developer's choice, so ask before passing `trail:`. Below `lg:` the
335
+ names, is the developer's choice, so ask before passing `trail:`. Check
336
+ first whether the app's Keystone UI initializer sets a `trail_supplier`,
337
+ which supplies a trail for every request: if it
338
+ does, a screen whose supplied trail is right passes neither `trail:` nor
339
+ `back_url:`, and passes its own only where the supplied one is wrong. If the
340
+ app supplies no trail, every form and detail screen passes `back_url:` or
341
+ `trail:`. Setting up a supplied trail is `keystone_ui-install`'s job. Below `lg:` the
311
342
  back link comes from `ui_mobile_header`, which the navbar renders from the
312
343
  title and back URL these shells publish. Check the app's layout: if it does not
313
344
  already render `ui_mobile_header` from that published context, ask the
@@ -26,9 +26,14 @@ separate mobile and desktop treatments (a bottom tab bar and mobile header on
26
26
  small screens, a full navigation bar from the `lg:` breakpoint up), because
27
27
  these apps are often viewed in a native webview. The form and show page shells
28
28
  follow the same split for going back: the mobile header carries the back link on
29
- small screens, and the shell renders a "Back" link above the title from `lg:` up.
30
- Given a trail of earlier pages instead, the shell renders breadcrumbs there in
31
- place of that link, ending with the page's own title.
29
+ small screens, and from `lg:` up the shell shows a "Back" link. Given a trail of
30
+ earlier pages instead, the shell shows breadcrumbs in place of that link, ending
31
+ with the page's own title. A page that passes no trail gets the one the app or
32
+ another gem supplies for the request, if any, and a page that passes no back
33
+ link goes back to that trail's last link. A trail or back link the page passes
34
+ itself always wins. Supplying a trail is set up through the install local. That link or those breadcrumbs, and the form page's
35
+ title, appear at the top of the page container, inside its width and padding, so
36
+ a page using either shell also uses the page container.
32
37
 
33
38
  ## Interface
34
39
 
@@ -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 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 and extra Tailwind imports and sources.
4
4
  tools: Bash, Read, Edit
5
5
  scope: UI — pages, forms, tables, navigation, dashboards
6
6
  ---
@@ -24,6 +24,8 @@ built on ViewComponent; hook it in before building any screen with those helpers
24
24
  custom mode),
25
25
  `register_look` (a look's CSS file by name), `default_look` and
26
26
  `look_supplier` (which registered look a page gets),
27
+ `trail_supplier` (a callable that supplies the breadcrumb trail for form and
28
+ show pages that pass none),
27
29
  and the `tailwind_imports` and `tailwind_sources` lists (extra CSS files and
28
30
  scan paths added to the Tailwind build).
29
31
  - `keystone_theme_attributes` — a layout helper placed inside the `<html>` tag.
@@ -176,6 +178,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
176
178
  config.register_look :compact, "/absolute/path/to/compact.css"
177
179
  config.default_look = :compact
178
180
  config.look_supplier = ->(view) { view.current_user&.look }
181
+ config.trail_supplier = ->(view) { view.breadcrumb_trail }
179
182
  config.tailwind_imports << "/absolute/path/to/extra.css"
180
183
  config.tailwind_sources << "/absolute/path/to/components/**/*.{erb,rb}"
181
184
  end
@@ -205,6 +208,14 @@ built on ViewComponent; hook it in before building any screen with those helpers
205
208
  - `look_supplier` — a callable that receives the view and returns a look
206
209
  name for the request. A name that is not registered, or `nil`, leaves the
207
210
  page on the default look.
211
+ - `trail_supplier` — a callable that receives the view and returns the
212
+ breadcrumb trail as an array of `[label, href]` pairs, or `nil`. A form or
213
+ show page that passes no trail of its own shows the supplied one on `lg:`
214
+ screens, ending with the page's title, in place of the desktop "Back" link.
215
+ A page that passes no Back link goes back to the trail's last link. A page
216
+ that passes its own trail or Back link keeps it. With no supplier, or a
217
+ `nil` return, the page shows its Back link. Ask the developer
218
+ which code in the app knows each page's trail before writing the callable.
208
219
  - `tailwind_imports` and `tailwind_sources` — lists to append to, never
209
220
  assign. Each import becomes an `@import` line and each source becomes an
210
221
  `@source` line in `keystone_source.css` on the next boot. They are for
@@ -114,6 +114,7 @@ sources:
114
114
  - app/components/keystone/ui/navbar_component.rb
115
115
  - app/components/keystone/ui/option_card_component.rb
116
116
  - app/components/keystone/ui/page_component.rb
117
+ - app/components/keystone/ui/page_component.html.erb
117
118
  - app/components/keystone/ui/page_header_component.rb
118
119
  - app/components/keystone/ui/panel_component.rb
119
120
  - app/components/keystone/ui/pipeline_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.21.0
4
+ version: 0.22.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Schneider