keystone_ui 0.29.5 → 0.30.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/assets/javascripts/keystone_ui/line_chart_controller.js +19 -6
- data/app/components/keystone/ui/line_chart_component.html.erb +1 -1
- data/app/components/keystone/ui/line_chart_component.rb +18 -3
- data/lib/keystone_ui/version.rb +1 -1
- data/the_local/agents/keystone_ui-develop.md +20 -4
- data/the_local/agents/keystone_ui-info.md +10 -0
- data/the_local/agents/keystone_ui-install.md +1 -1
- data/the_local/interface.yml +1 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 53f39974ced2866fb949b3bfbe0e1be0359977df8a890f9bf83e20b8a04cff11
|
|
4
|
+
data.tar.gz: 7dc3d1ae90c88bd89ccff1c67a861f6e391558605edb5aaaa136f3c674e47cb6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ce349e68888fb9085cf9475eb3a96cb6dec23e193df5912905e559f5371dcb7d936d7e6b80a09d820fa28a91da0993c67add11578729dd37e62f25b3d7bac787
|
|
7
|
+
data.tar.gz: 37cfadba853c471e4ba8a4e9cf94c941e9a554151a76ba9bba4573b80bf80b49850ac713a55da7f148b3aabd6fb253a36b1089c5c132f0afa86d1072aa6e6216
|
|
@@ -6,9 +6,26 @@ const loadChart = async () => {
|
|
|
6
6
|
return Chart
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
const MILLISECONDS_IN_A_DAY = 86_400_000
|
|
10
|
+
|
|
11
|
+
export const dayLabel = (day) =>
|
|
12
|
+
new Date(day * MILLISECONDS_IN_A_DAY).toLocaleDateString("en-US", { timeZone: "UTC", month: "short", day: "numeric", year: "numeric" })
|
|
13
|
+
|
|
14
|
+
const DATED_OPTIONS = {
|
|
15
|
+
scales: { x: { type: "linear", bounds: "data", ticks: { precision: 0, callback: dayLabel } } },
|
|
16
|
+
plugins: { tooltip: { callbacks: { title: ([point]) => dayLabel(point.parsed.x) } } }
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const chartOptions = (dated) => ({
|
|
20
|
+
responsive: true,
|
|
21
|
+
maintainAspectRatio: false,
|
|
22
|
+
interaction: { mode: "index", intersect: false },
|
|
23
|
+
...(dated ? DATED_OPTIONS : {})
|
|
24
|
+
})
|
|
25
|
+
|
|
9
26
|
export default class extends Controller {
|
|
10
27
|
static targets = ["canvas"]
|
|
11
|
-
static values = { data: Object }
|
|
28
|
+
static values = { data: Object, dated: Boolean }
|
|
12
29
|
|
|
13
30
|
async connect() {
|
|
14
31
|
const Chart = await loadChart()
|
|
@@ -17,11 +34,7 @@ export default class extends Controller {
|
|
|
17
34
|
this.chart = new Chart(this.canvasTarget, {
|
|
18
35
|
type: "line",
|
|
19
36
|
data: this.resolveColors(this.dataValue),
|
|
20
|
-
options:
|
|
21
|
-
responsive: true,
|
|
22
|
-
maintainAspectRatio: false,
|
|
23
|
-
interaction: { mode: "index", intersect: false }
|
|
24
|
-
}
|
|
37
|
+
options: chartOptions(this.datedValue)
|
|
25
38
|
})
|
|
26
39
|
}
|
|
27
40
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
<div class="<%= container_classes %>" data-controller="line-chart" data-line-chart-data-value="<%= chart_data_json %>">
|
|
1
|
+
<div class="<%= container_classes %>" data-controller="line-chart" data-line-chart-data-value="<%= chart_data_json %>" data-line-chart-dated-value="<%= dated? %>">
|
|
2
2
|
<canvas class="max-w-full" data-line-chart-target="canvas"></canvas>
|
|
3
3
|
</div>
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "date"
|
|
3
4
|
require "json"
|
|
4
5
|
|
|
5
6
|
module Keystone
|
|
@@ -12,21 +13,29 @@ module Keystone
|
|
|
12
13
|
}.freeze
|
|
13
14
|
|
|
14
15
|
DASH_PATTERN = [ 6, 6 ].freeze
|
|
16
|
+
EPOCH = Date.new(1970, 1, 1)
|
|
17
|
+
|
|
18
|
+
def initialize(series:, labels: nil, dates: nil, height: :md)
|
|
19
|
+
raise ArgumentError, "a line chart takes labels: or dates:" unless labels.nil? ^ dates.nil?
|
|
15
20
|
|
|
16
|
-
def initialize(series:, labels:, height: :md)
|
|
17
21
|
@series = series
|
|
18
22
|
@labels = labels
|
|
23
|
+
@dates = dates
|
|
19
24
|
@height = height
|
|
20
25
|
end
|
|
21
26
|
|
|
22
27
|
def chart_data
|
|
23
|
-
{ labels: @labels, datasets: @series.map { |s| dataset_for(s) } }
|
|
28
|
+
{ labels: @labels, datasets: @series.map { |s| dataset_for(s) } }.compact
|
|
24
29
|
end
|
|
25
30
|
|
|
26
31
|
def chart_data_json
|
|
27
32
|
chart_data.to_json
|
|
28
33
|
end
|
|
29
34
|
|
|
35
|
+
def dated?
|
|
36
|
+
!@dates.nil?
|
|
37
|
+
end
|
|
38
|
+
|
|
30
39
|
def height_class
|
|
31
40
|
HEIGHT_CLASSES.fetch(@height)
|
|
32
41
|
end
|
|
@@ -38,11 +47,17 @@ module Keystone
|
|
|
38
47
|
private
|
|
39
48
|
|
|
40
49
|
def dataset_for(series)
|
|
41
|
-
dataset = { label: series[:name], data: series[:data] }
|
|
50
|
+
dataset = { label: series[:name], data: points_for(series[:data]) }
|
|
42
51
|
dataset[:borderColor] = series[:color] if series[:color]
|
|
43
52
|
dataset[:borderDash] = DASH_PATTERN if series[:dashed]
|
|
44
53
|
dataset
|
|
45
54
|
end
|
|
55
|
+
|
|
56
|
+
def points_for(values)
|
|
57
|
+
return values unless @dates
|
|
58
|
+
|
|
59
|
+
@dates.zip(values).map { |date, value| { x: (date.to_date - EPOCH).to_i, y: value } }
|
|
60
|
+
end
|
|
46
61
|
end
|
|
47
62
|
end
|
|
48
63
|
end
|
data/lib/keystone_ui/version.rb
CHANGED
|
@@ -323,10 +323,20 @@ outer element. See Conventions before using it.
|
|
|
323
323
|
|
|
324
324
|
- `ui_chart_card(title:, height: :md)` — takes a block holding a chart. `height:`
|
|
325
325
|
`:sm` `:md` `:lg`.
|
|
326
|
-
- `ui_line_chart(series:, labels
|
|
327
|
-
|
|
328
|
-
`
|
|
329
|
-
`
|
|
326
|
+
- `ui_line_chart(series:, labels: nil, dates: nil, height: :md)` — a line chart
|
|
327
|
+
with one line per series. `series:` is
|
|
328
|
+
`[{ name:, data:, color:, dashed: }, ...]` where `data:` is the array of
|
|
329
|
+
values, and `color:` (a CSS color string for the line) and `dashed: true` are
|
|
330
|
+
optional. `height:` `:sm` `:md` `:lg`. Pass exactly one of `labels:` and
|
|
331
|
+
`dates:` for the horizontal axis: passing both, or neither, raises
|
|
332
|
+
`ArgumentError`. `labels:` is an array of strings, one per value, spaced
|
|
333
|
+
evenly and shown as written. `dates:` is an array of `Date`, `Time` or
|
|
334
|
+
`DateTime` values, one per value, matched to each series' `data:` by
|
|
335
|
+
position. A dated chart places each point by its day, so a gap of a week is
|
|
336
|
+
seven times as wide as a gap of a day. Its axis runs from the first day to
|
|
337
|
+
the last, marks only whole days, and reads each day as a date such as
|
|
338
|
+
"Oct 2, 2026", which is also the heading a hovered point shows. The time of
|
|
339
|
+
day is dropped, so pass one value per day.
|
|
330
340
|
- `ui_funnel(steps:)` — a conversion funnel. `steps:` is
|
|
331
341
|
`[{ label:, value:, color: }, ...]` in order, with `color:` optional. Bar
|
|
332
342
|
widths are relative to the first step; the caption between two layers is the
|
|
@@ -443,6 +453,12 @@ outer element. See Conventions before using it.
|
|
|
443
453
|
On a radio card or a checkbox row, text every reader needs to choose goes in `hint:` and
|
|
444
454
|
text only some will want goes in `info:`. Which is which is the app's own
|
|
445
455
|
wording, so ask the developer rather than pick.
|
|
456
|
+
For a line chart, pass `dates:` when each value belongs to a calendar day
|
|
457
|
+
and `labels:` when the horizontal axis is anything else, such as week names
|
|
458
|
+
or categories. With `dates:`, a day with no value leaves a wider gap between
|
|
459
|
+
its neighbours rather than a point at zero. Whether a missing day is left
|
|
460
|
+
out or passed as a zero is the app's own rule, so ask the developer rather
|
|
461
|
+
than pick. Never format dates into strings and pass them as `labels:`.
|
|
446
462
|
Put the actions on a record, such as Edit and Delete, in an action menu
|
|
447
463
|
rather than in a row of buttons: `menu:` on the `ui_section` that shows the
|
|
448
464
|
record, `table.actions` for a table row, or `ui_action_menu` anywhere else.
|
|
@@ -129,6 +129,16 @@ 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 line chart is labelled or dated.** A line chart draws one line per
|
|
133
|
+
series, and each series is a name and its values, with an optional colour
|
|
134
|
+
and an optional dashed line. Its horizontal axis is given one of two ways,
|
|
135
|
+
never both and never neither, and the wrong combination raises
|
|
136
|
+
`ArgumentError`. Labels are text, one per value, spaced evenly and shown as
|
|
137
|
+
written. Dates are one day per value, and a dated chart places each point by
|
|
138
|
+
its day, so a gap of a week is seven times as wide as a gap of a day. A dated
|
|
139
|
+
axis runs from the first day to the last, marks only whole days, and reads
|
|
140
|
+
each day as a date such as "Oct 2, 2026", which is also what a hovered point
|
|
141
|
+
shows. A time of day is dropped, so a dated chart has one position per day.
|
|
132
142
|
- **A calculation is text.** The calculation behind a figure is the opposite
|
|
133
143
|
case. It is a list of groups, each with an optional title and its lines, and
|
|
134
144
|
each line is a label, the working and the result. They are passed as
|
|
@@ -40,7 +40,7 @@ built on ViewComponent; hook it in before building any screen with those helpers
|
|
|
40
40
|
## How to use it
|
|
41
41
|
|
|
42
42
|
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.
|
|
43
|
+
host app. The gem brings ViewComponent and keystone_ui-styles 0.9.0 or later with it.
|
|
44
44
|
Tailwind does not have to be initialized first, because the generator creates
|
|
45
45
|
the stylesheet if it is missing.
|
|
46
46
|
|
data/the_local/interface.yml
CHANGED
|
@@ -98,6 +98,7 @@ sources:
|
|
|
98
98
|
- app/components/keystone/ui/info_component.rb
|
|
99
99
|
- app/components/keystone/ui/info_component.html.erb
|
|
100
100
|
- app/assets/javascripts/keystone_ui/info_controller.js
|
|
101
|
+
- app/assets/javascripts/keystone_ui/line_chart_controller.js
|
|
101
102
|
- app/components/keystone/ui/breakdown_component.rb
|
|
102
103
|
- app/components/keystone/ui/breakdown_component.html.erb
|
|
103
104
|
- app/components/keystone/ui/feature_grid_component.rb
|