keystone_ui 0.20.0 → 0.21.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: 2831a7bc53b87bd905d8b270f78c26d1d47a8fe32bff2bf53c60093b8c84cf03
4
- data.tar.gz: 36cf740c39fbeb33f4cc27d9ea4942e3ddfac9712856c195de49d3cde4989f66
3
+ metadata.gz: 3ebe6bbc917891684b563a1981daf0cc0b32a747143f52d72af17bd2a9df2e7d
4
+ data.tar.gz: 0320fdf4a5c56b52e6919641022b1fbd05dd2ccdcb5c8b91553f696d3ab3e115
5
5
  SHA512:
6
- metadata.gz: ddf44be2fc4062b9ab5655f72d613dad4d6e367cfd138c95513adfd1cb749df42c7b1309972d688b629247b792cceba97f568c55850609209e6e1ae9426972c9
7
- data.tar.gz: 70507b228b07861f2ca48449bfa3dbeb0b28019bd5f3a5a22eaf2cfa4ba852d160a7401ec0058c7a8e832afea1a06e1c548b312bab74a8f5efa93d5f05f903b1
6
+ metadata.gz: b6b75345f8165d8ae02e9d7a7e6fe24a015f37f07437082dcad6d3543fa17b56013073ef9c69729be5b330b1959f69e0bb33d628df176d01fe69ae296c33713a
7
+ data.tar.gz: 04b8b2e35b0d24fcb507d0293142aba61723ed1737478da8376bce4b6533b97fe12ca2efe9a629c92916b1aba4fdee8f47ec7bbf85c8e74bb39e60d409ae9375
@@ -0,0 +1,14 @@
1
+ <nav aria-label="Breadcrumb" class="<%= CLASSES %>">
2
+ <% @trail.each_with_index do |(label, href), index| %>
3
+ <% if index.positive? %>
4
+ <span aria-hidden="true"><%= SEPARATOR %></span>
5
+ <% end %>
6
+ <%= link_to label, href %>
7
+ <% end %>
8
+ <% if @current %>
9
+ <% if @trail.any? %>
10
+ <span aria-hidden="true"><%= SEPARATOR %></span>
11
+ <% end %>
12
+ <span aria-current="page"><%= @current %></span>
13
+ <% end %>
14
+ </nav>
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Keystone
4
+ module Ui
5
+ class BreadcrumbsComponent < ViewComponent::Base
6
+ CLASSES = "ks-mobile-header-back hidden lg:block text-sm"
7
+ SEPARATOR = "›"
8
+
9
+ def initialize(trail:, current: nil)
10
+ @trail = trail
11
+ @current = current
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+ <%= link_to @url, class: CLASSES do %>
2
+ <%= Keystone::Ui::MobileHeaderComponent::BACK_ICON.html_safe %>
3
+ <%= LABEL %>
4
+ <% end %>
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Keystone
4
+ module Ui
5
+ class DesktopBackLinkComponent < ViewComponent::Base
6
+ CLASSES = "ks-mobile-header-back hidden lg:inline-flex items-center"
7
+ LABEL = "Back"
8
+
9
+ def initialize(url:)
10
+ @url = url
11
+ end
12
+ end
13
+ end
14
+ end
@@ -2,6 +2,12 @@
2
2
  <% content_for :form_page_title, @title %>
3
3
  <% content_for :form_page_back_url, @back_url %>
4
4
 
5
+ <% if @trail %>
6
+ <%= render Keystone::Ui::BreadcrumbsComponent.new(trail: @trail, current: @title) %>
7
+ <% else %>
8
+ <%= render Keystone::Ui::DesktopBackLinkComponent.new(url: @back_url) %>
9
+ <% end %>
10
+
5
11
  <div class="<%= DESKTOP_WRAPPER_CLASSES %>">
6
12
  <h1 class="<%= TITLE_CLASSES %>"><%= @title %></h1>
7
13
  <% if subtitle? %>
@@ -7,10 +7,11 @@ 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)
10
+ def initialize(title:, back_url:, subtitle: nil, trail: nil)
11
11
  @title = title
12
12
  @back_url = back_url
13
13
  @subtitle = subtitle
14
+ @trail = trail
14
15
  end
15
16
 
16
17
  def subtitle?
@@ -2,3 +2,9 @@
2
2
  <% content_for :show_page_title, @title %>
3
3
  <% content_for :show_page_back_url, @back_url %>
4
4
  <% content_for :show_page_subtitle, @subtitle if @subtitle.present? %>
5
+
6
+ <% if @trail %>
7
+ <%= render Keystone::Ui::BreadcrumbsComponent.new(trail: @trail, current: @title) %>
8
+ <% else %>
9
+ <%= render Keystone::Ui::DesktopBackLinkComponent.new(url: @back_url) %>
10
+ <% end %>
@@ -7,10 +7,11 @@ 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)
10
+ def initialize(title:, back_url:, subtitle: nil, trail: nil)
11
11
  @title = title
12
12
  @back_url = back_url
13
13
  @subtitle = subtitle
14
+ @trail = trail
14
15
  end
15
16
 
16
17
  def subtitle?
@@ -117,6 +117,10 @@ module KeystoneUiHelper
117
117
  render Keystone::Ui::ShowPageComponent.new(**args)
118
118
  end
119
119
 
120
+ def ui_breadcrumbs(**args)
121
+ render Keystone::Ui::BreadcrumbsComponent.new(**args)
122
+ end
123
+
120
124
  def ui_mobile_header(**args)
121
125
  render Keystone::Ui::MobileHeaderComponent.new(**args)
122
126
  end
@@ -57,7 +57,9 @@ module Keystone
57
57
  Keystone::Ui::CodeComponent,
58
58
  Keystone::Ui::DisclosureComponent,
59
59
  Keystone::Ui::ThemeToggleComponent,
60
- Keystone::Ui::CalculationComponent
60
+ Keystone::Ui::CalculationComponent,
61
+ Keystone::Ui::DesktopBackLinkComponent,
62
+ Keystone::Ui::BreadcrumbsComponent
61
63
  ].freeze
62
64
 
63
65
  # Constants that hold non-CSS values (e.g. HTML input type maps)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KeystoneUi
4
- VERSION = "0.20.0"
4
+ VERSION = "0.21.0"
5
5
  end
@@ -62,12 +62,23 @@ outer element. See Conventions before using it.
62
62
  `sm:`). Call `header.action { ... }` in the block to place a custom control on
63
63
  the right; only what `action` receives is rendered. Passing `action_url:`
64
64
  publishes that URL and label for a mobile navbar to pick up.
65
- - `ui_form_page(title:, back_url:, subtitle: nil)` — the shell marker for a form
66
- screen. Renders the desktop title block and publishes the title and back URL so
67
- the navbar can render mobile header context.
68
- - `ui_show_page(title:, back_url:, subtitle: nil)` — the shell marker for a
69
- detail screen. Renders nothing itself; only publishes the title, subtitle, and
70
- back URL for the navbar.
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.
77
+ - `ui_breadcrumbs(trail:, current: nil)` — a line of links shown only from `lg:`
78
+ up. `trail:` is `[[label, href], ...]`, from the top level down, and each pair
79
+ renders as a link, separated by `›`. `current:` is the page being shown,
80
+ rendered last, unlinked, and marked as the current page. On a form or detail
81
+ screen pass `trail:` to the shell instead of calling this helper.
71
82
 
72
83
  ### Navigation
73
84
 
@@ -293,8 +304,12 @@ outer element. See Conventions before using it.
293
304
  - a detail screen → `ui_show_page`
294
305
  - anything else → `ui_page`, with `ui_page_header` for the desktop title.
295
306
 
296
- `ui_form_page` and `ui_show_page` publish their title and back URL for the
297
- navbar to render as a mobile header. Check the app's layout: if it does not
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
309
+ 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
311
+ back link comes from `ui_mobile_header`, which the navbar renders from the
312
+ title and back URL these shells publish. Check the app's layout: if it does not
298
313
  already render `ui_mobile_header` from that published context, ask the
299
314
  developer whether to wire it before adding more screens that depend on it.
300
315
 
@@ -369,7 +384,7 @@ outer element. See Conventions before using it.
369
384
  through it, so anything else emitted inside their block is discarded.
370
385
  - **Mobile is not an afterthought.** Several helpers render only on one side of
371
386
  the `lg:` (or `sm:`) breakpoint — page headers, mobile headers, mobile actions,
372
- bottom navigation. A screen needs both treatments; check the small viewport
387
+ bottom navigation, breadcrumbs. A screen needs both treatments; check the small viewport
373
388
  before calling it done.
374
389
  - Out of scope for this local: installing or upgrading the gem, changing the
375
390
  palette or theme defaults, and editing the components themselves. Building a
@@ -13,7 +13,7 @@ It changes nothing and gives no steps.
13
13
  Keystone UI is a Rails engine gem that supplies a host app's visual layer as a
14
14
  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
- navigation bars, cards, stat tiles, charts, funnels, goal buckets, pipelines,
16
+ navigation bars, breadcrumbs, cards, stat tiles, charts, funnels, goal buckets, pipelines,
17
17
  banners, the calculation behind a figure — instead of hand-written ERB and
18
18
  Tailwind. Every class the UI renders lives inside the gem, in frozen constants,
19
19
  so the look is defined in one place.
@@ -24,7 +24,11 @@ cannot disagree about spacing, color or dark-mode treatment, and a change to a
24
24
  component updates every page that uses it. It is mobile-first — components ship
25
25
  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
- these apps are often viewed in a native webview.
27
+ these apps are often viewed in a native webview. The form and show page shells
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.
28
32
 
29
33
  ## Interface
30
34
 
@@ -91,7 +95,7 @@ holds the catalog.
91
95
  chart card, card link, CTA banner, feature grid, hero, data table, code,
92
96
  accordion, disclosure, calculation, tab switcher, progress, funnel, bucket,
93
97
  pipeline and swipe deck. So do the navigation components: navbar, nav item,
94
- nav dropdown, bottom nav, mobile header and settings link. A host imports its
98
+ nav dropdown, bottom nav, mobile header, breadcrumbs and settings link. A host imports its
95
99
  look after `keystone_source.css`, and a gem ships one through
96
100
  `tailwind_imports`, both set up through the install local.
97
101
  - **Registered looks.** Looks can also be registered by name, and each page
@@ -154,8 +154,9 @@ built on ViewComponent; hook it in before building any screen with those helpers
154
154
  disclosure, calculation, tab switcher, progress, funnel, bucket, pipeline and
155
155
  swipe deck.
156
156
  So do the navigation components: navbar, nav item, nav dropdown, bottom nav,
157
- mobile header and settings link. The keystone_ui-styles README lists every
158
- variable and its default.
157
+ mobile header and settings link. The desktop "Back" link and the breadcrumbs
158
+ on form and show pages use the mobile header's back link variables. The
159
+ keystone_ui-styles README lists every variable and its default.
159
160
 
160
161
  To offer several looks and choose one per page, register them by name in
161
162
  step 7 rather than importing them here.
@@ -197,6 +198,10 @@ built on ViewComponent; hook it in before building any screen with those helpers
197
198
  this way scopes its variables to `:root[data-look="<name>"]` instead of
198
199
  `:root`, so several can be imported at once.
199
200
  - `default_look = :name` — the look a page gets when nothing else chooses one.
201
+ - The app refuses to boot when `default_look` names a look that is not
202
+ registered, when a registered look's file does not exist, or when the file
203
+ sets no `--ks-` variable inside a `:root[data-look="<name>"]` rule. Use an
204
+ absolute path for each look file.
200
205
  - `look_supplier` — a callable that receives the view and returns a look
201
206
  name for the request. A name that is not registered, or `nil`, leaves the
202
207
  page on the default look.
@@ -33,6 +33,7 @@ develop:
33
33
  - ui_alert
34
34
  - ui_form_page
35
35
  - ui_show_page
36
+ - ui_breadcrumbs
36
37
  - ui_mobile_header
37
38
  - ui_mobile_actions
38
39
  - ui_navbar
@@ -92,6 +93,11 @@ sources:
92
93
  - app/components/keystone/ui/form_component.rb
93
94
  - app/components/keystone/ui/form_field_component.rb
94
95
  - app/components/keystone/ui/form_page_component.rb
96
+ - app/components/keystone/ui/form_page_component.html.erb
97
+ - app/components/keystone/ui/desktop_back_link_component.rb
98
+ - app/components/keystone/ui/desktop_back_link_component.html.erb
99
+ - app/components/keystone/ui/breadcrumbs_component.rb
100
+ - app/components/keystone/ui/breadcrumbs_component.html.erb
95
101
  - app/components/keystone/ui/funnel_component.rb
96
102
  - app/components/keystone/ui/bucket_component.rb
97
103
  - app/components/keystone/ui/bucket_series_component.rb
@@ -118,6 +124,7 @@ sources:
118
124
  - app/components/keystone/ui/select_component.rb
119
125
  - app/components/keystone/ui/settings_link_component.rb
120
126
  - app/components/keystone/ui/show_page_component.rb
127
+ - app/components/keystone/ui/show_page_component.html.erb
121
128
  - app/components/keystone/ui/stat_card_component.rb
122
129
  - app/components/keystone/ui/stat_card_component.html.erb
123
130
  - app/components/keystone/ui/swipe_deck_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.20.0
4
+ version: 0.21.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Schneider
@@ -81,6 +81,8 @@ files:
81
81
  - app/components/keystone/ui/bottom_nav_component.rb
82
82
  - app/components/keystone/ui/bottom_nav_item_component.html.erb
83
83
  - app/components/keystone/ui/bottom_nav_item_component.rb
84
+ - app/components/keystone/ui/breadcrumbs_component.html.erb
85
+ - app/components/keystone/ui/breadcrumbs_component.rb
84
86
  - app/components/keystone/ui/bucket_component.html.erb
85
87
  - app/components/keystone/ui/bucket_component.rb
86
88
  - app/components/keystone/ui/bucket_series_component.html.erb
@@ -110,6 +112,8 @@ files:
110
112
  - app/components/keystone/ui/cta_banner_component.rb
111
113
  - app/components/keystone/ui/data_table_component.html.erb
112
114
  - app/components/keystone/ui/data_table_component.rb
115
+ - app/components/keystone/ui/desktop_back_link_component.html.erb
116
+ - app/components/keystone/ui/desktop_back_link_component.rb
113
117
  - app/components/keystone/ui/disclosure_component.html.erb
114
118
  - app/components/keystone/ui/disclosure_component.rb
115
119
  - app/components/keystone/ui/feature_grid_component.html.erb