keystone_ui 0.30.0 → 0.31.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: 53f39974ced2866fb949b3bfbe0e1be0359977df8a890f9bf83e20b8a04cff11
4
- data.tar.gz: 7dc3d1ae90c88bd89ccff1c67a861f6e391558605edb5aaaa136f3c674e47cb6
3
+ metadata.gz: a6c7e18e911657e41ed1a4eff2133400015bd7a58e0c437f6886d219173f01fa
4
+ data.tar.gz: 91b2f652bb7313d9cda361e126e969d06b64827e80118888a73cce3840471f68
5
5
  SHA512:
6
- metadata.gz: ce349e68888fb9085cf9475eb3a96cb6dec23e193df5912905e559f5371dcb7d936d7e6b80a09d820fa28a91da0993c67add11578729dd37e62f25b3d7bac787
7
- data.tar.gz: 37cfadba853c471e4ba8a4e9cf94c941e9a554151a76ba9bba4573b80bf80b49850ac713a55da7f148b3aabd6fb253a36b1089c5c132f0afa86d1072aa6e6216
6
+ metadata.gz: 466ea8fbb32ed4683db9537a52d7ba41d667f79dfa52aec27aaab85f5fc14b872fcc03b7d880136936133685fdc1af5f839aa4392c5ba698af62694e4a5832b0
7
+ data.tar.gz: 435630df203142fa669f0d93333e6b2637b2d4ec2d25b6e8fa1a7aa00e54ba5fdace3a3416905c144f706f18373ad78b8b11c067f5d1a62ee6453655358b4b77
@@ -1,14 +1,35 @@
1
- <div class="<%= container_classes %>">
2
- <% layers.each do |layer| %>
3
- <% if layer.conversion_percent %>
4
- <div class="<%= transition_classes %>">↓ <%= layer.conversion_percent %>%</div>
5
- <% end %>
6
- <div class="<%= layer_classes %>">
7
- <div class="<%= row_classes %>">
8
- <span class="<%= label_classes %>"><%= layer.label %></span>
1
+ <% if joined? %>
2
+ <div class="<%= JOINED_CLASSES %>">
3
+ <% layers.each do |layer| %>
4
+ <% if layer.conversion_percent %>
5
+ <div></div>
6
+ <div class="<%= BAND_ROW_CLASSES %>">
7
+ <div class="<%= BAND_CLASSES %>" style="clip-path: <%= band_clip_path(layer) %>"></div>
8
+ <div class="<%= BAND_LABEL_ROW_CLASSES %>"><span class="<%= BAND_LABEL_CLASSES %>"><%= layer.conversion_percent %>%</span></div>
9
+ </div>
10
+ <% end %>
11
+ <div class="<%= WORDS_CLASSES %>">
9
12
  <span class="<%= value_classes %>"><%= layer.value %></span>
13
+ <span class="<%= label_classes %>"><%= layer.label %></span>
14
+ </div>
15
+ <div class="<%= BLOCK_CLASSES %>">
16
+ <div class="<%= BLOCK_FILL_CLASSES %> <%= layer.color_classes %>" style="width: <%= layer.width_percent %>%"></div>
10
17
  </div>
11
- <div class="<%= bar_classes %> <%= layer.color_classes %>" style="width: <%= layer.width_percent %>%"></div>
12
- </div>
13
- <% end %>
14
- </div>
18
+ <% end %>
19
+ </div>
20
+ <% else %>
21
+ <div class="<%= container_classes %>">
22
+ <% layers.each do |layer| %>
23
+ <% if layer.conversion_percent %>
24
+ <div class="<%= transition_classes %>">↓ <%= layer.conversion_percent %>%</div>
25
+ <% end %>
26
+ <div class="<%= layer_classes %>">
27
+ <div class="<%= row_classes %>">
28
+ <span class="<%= label_classes %>"><%= layer.label %></span>
29
+ <span class="<%= value_classes %>"><%= layer.value %></span>
30
+ </div>
31
+ <div class="<%= bar_classes %> <%= layer.color_classes %>" style="width: <%= layer.width_percent %>%"></div>
32
+ </div>
33
+ <% end %>
34
+ </div>
35
+ <% end %>
@@ -3,7 +3,7 @@
3
3
  module Keystone
4
4
  module Ui
5
5
  class FunnelComponent < ViewComponent::Base
6
- Layer = Struct.new(:label, :value, :width_percent, :conversion_percent, :color_classes, keyword_init: true)
6
+ Layer = Struct.new(:label, :value, :width_percent, :conversion_percent, :color_classes, :previous_width_percent, keyword_init: true)
7
7
 
8
8
  CONTAINER_CLASSES = "ks-funnel"
9
9
  LAYER_CLASSES = "ks-funnel-layer"
@@ -12,6 +12,14 @@ module Keystone
12
12
  VALUE_CLASSES = "ks-funnel-value text-sm tabular-nums"
13
13
  BAR_CLASSES = "ks-funnel-bar h-8 transition-all"
14
14
  TRANSITION_CLASSES = "ks-funnel-transition text-center text-xs"
15
+ BAND_LABEL_ROW_CLASSES = "absolute inset-0 flex items-center justify-center"
16
+ BAND_ROW_CLASSES = "relative h-7"
17
+ BLOCK_FILL_CLASSES = "h-full"
18
+ BLOCK_CLASSES = "flex justify-center h-12"
19
+ WORDS_CLASSES = "flex flex-col justify-center"
20
+ BAND_LABEL_CLASSES = "ks-funnel-band-label text-xs"
21
+ BAND_CLASSES = "ks-funnel-band absolute inset-0"
22
+ JOINED_CLASSES = "ks-funnel-joined grid grid-cols-[max-content_1fr]"
15
23
  STEP_COLOR_CLASSES = {
16
24
  accent: "ks-funnel-bar-accent",
17
25
  sky: "ks-funnel-bar-sky",
@@ -20,10 +28,24 @@ module Keystone
20
28
  rose: "ks-funnel-bar-rose"
21
29
  }.freeze
22
30
 
23
- attr_reader :steps
31
+ attr_reader :steps, :shape
32
+
33
+ def initialize(steps:, shape: :bars)
34
+ raise ArgumentError, "a funnel's shape is :bars or :joined, got #{shape.inspect}" unless %i[bars joined].include?(shape)
24
35
 
25
- def initialize(steps:)
26
36
  @steps = steps
37
+ @shape = shape
38
+ end
39
+
40
+ def joined?
41
+ shape == :joined
42
+ end
43
+
44
+ def band_clip_path(layer)
45
+ top = (100 - layer.previous_width_percent) / 2.0
46
+ bottom = (100 - layer.width_percent) / 2.0
47
+
48
+ "polygon(#{format("%g%%", top)} 0, #{format("%g%%", 100 - top)} 0, #{format("%g%%", 100 - bottom)} 100%, #{format("%g%%", bottom)} 100%)"
27
49
  end
28
50
 
29
51
  def layers
@@ -35,7 +57,8 @@ module Keystone
35
57
  value: step[:value],
36
58
  width_percent: width_percent(step[:value]),
37
59
  conversion_percent: conversion_percent(step[:value], previous),
38
- color_classes: color_classes(step[:color], index)
60
+ color_classes: color_classes(step[:color], index),
61
+ previous_width_percent: previous && width_percent(previous)
39
62
  )
40
63
  previous = step[:value]
41
64
  layer
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KeystoneUi
4
- VERSION = "0.30.0"
4
+ VERSION = "0.31.0"
5
5
  end
@@ -337,13 +337,20 @@ outer element. See Conventions before using it.
337
337
  the last, marks only whole days, and reads each day as a date such as
338
338
  "Oct 2, 2026", which is also the heading a hovered point shows. The time of
339
339
  day is dropped, so pass one value per day.
340
- - `ui_funnel(steps:)` — a conversion funnel. `steps:` is
341
- `[{ label:, value:, color: }, ...]` in order, with `color:` optional. Bar
342
- widths are relative to the first step; the caption between two layers is the
343
- step-to-step conversion. Each bar takes the next colour in the order
344
- `:accent` `:sky` `:violet` `:amber` `:rose`, starting again after `:rose`; a
345
- step passing one of those symbols as `color:` uses it instead, and any other
346
- symbol raises. Divide-by-zero safe, no JavaScript.
340
+ - `ui_funnel(steps:, shape: :bars)` — a conversion funnel. `steps:` is
341
+ `[{ label:, value:, color: }, ...]` in order, with `color:` optional. Each
342
+ step's width is its value as a share of the first step's value, and the
343
+ percent shown between two steps is the second step's value divided by the
344
+ first's. Each step takes the next colour in the order `:accent` `:sky`
345
+ `:violet` `:amber` `:rose`, starting again after `:rose`; a step passing one
346
+ of those symbols as `color:` uses it instead, and any other symbol raises.
347
+ Values are printed as given. Divide-by-zero safe, no JavaScript. `shape:`
348
+ `:bars` draws one bar per step, left-aligned, with the label and value on a
349
+ row above it and a `↓ N%` caption between two bars. `shape: :joined` draws
350
+ one shape: each step's value over its label in a column on the left, each
351
+ step's block centred at its width, and between two blocks a neutral band
352
+ that narrows from the block above to the block below, with the percent on it.
353
+ Any other `shape:` raises `ArgumentError`.
347
354
  - `ui_bucket(goal:, actual:, label: nil, over: :success)` — an upright container
348
355
  for one target, filled from the bottom toward `goal:`. It shows the optional
349
356
  `label` on top, then `goal`, the container, `actual`, and the percent reached.
@@ -459,6 +466,12 @@ outer element. See Conventions before using it.
459
466
  its neighbours rather than a point at zero. Whether a missing day is left
460
467
  out or passed as a zero is the app's own rule, so ask the developer rather
461
468
  than pick. Never format dates into strings and pass them as `labels:`.
469
+ For a funnel, whether it is drawn as separate bars or as one joined shape
470
+ is the developer's choice, so ask before passing `shape:`. If a joined
471
+ funnel shows its blocks but no band between them, the app's
472
+ keystone_ui-styles version does not define the `ks-funnel-band` classes, so
473
+ stop and hand that part to `keystone_ui-install`, and add no classes to fix
474
+ it.
462
475
  Put the actions on a record, such as Edit and Delete, in an action menu
463
476
  rather than in a row of buttons: `menu:` on the `ui_section` that shows the
464
477
  record, `table.actions` for a table row, or `ui_action_menu` anywhere else.
@@ -129,6 +129,13 @@ holds the catalog.
129
129
  - **Figures are numbers.** Components that measure or compare values, such as
130
130
  progress bars, funnels and buckets, do arithmetic on them. Pass a number, not
131
131
  a formatted string such as `"9,000"`. A bucket raises on one.
132
+ - **A funnel has two shapes.** Both size each step against the first step and
133
+ show the percent carried from one step to the next. The default draws one bar
134
+ per step, each with its label and value on a row above it. The joined shape
135
+ draws the steps as one figure: each step's value and label sit in a column on
136
+ the left, each step is a block centred at its width, and a neutral band
137
+ between two blocks narrows from one width to the next and holds the percent.
138
+ Any other shape raises `ArgumentError`. Neither shape needs JavaScript.
132
139
  - **A line chart is labelled or dated.** A line chart draws one line per
133
140
  series, and each series is a name and its values, with an optional colour
134
141
  and an optional dashed line. Its horizontal axis is given one of two ways,
@@ -112,6 +112,7 @@ sources:
112
112
  - app/components/keystone/ui/breadcrumbs_component.rb
113
113
  - app/components/keystone/ui/breadcrumbs_component.html.erb
114
114
  - app/components/keystone/ui/funnel_component.rb
115
+ - app/components/keystone/ui/funnel_component.html.erb
115
116
  - app/components/keystone/ui/bucket_component.rb
116
117
  - app/components/keystone/ui/bucket_series_component.rb
117
118
  - app/components/keystone/ui/grid_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.30.0
4
+ version: 0.31.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tyler Schneider
@@ -15,14 +15,14 @@ dependencies:
15
15
  requirements:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
- version: 0.9.0
18
+ version: 0.10.0
19
19
  type: :runtime
20
20
  prerelease: false
21
21
  version_requirements: !ruby/object:Gem::Requirement
22
22
  requirements:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
- version: 0.9.0
25
+ version: 0.10.0
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: view_component
28
28
  requirement: !ruby/object:Gem::Requirement