houseaccount 0.12.0 → 0.13.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/CHANGELOG.md +23 -0
- data/README.md +8 -0
- data/art/icons.txt +1 -0
- data/config/locales/houseaccount.en.yml +5 -0
- data/lib/houseaccount/form_builder/comboboxes.rb +38 -0
- data/lib/houseaccount/form_builder/controls.rb +67 -0
- data/lib/houseaccount/form_builder.rb +22 -10
- data/lib/houseaccount/version.rb +1 -1
- data/public/css/houseaccount.css +1 -1
- data/public/font/bootstrap-icons-FRBPO3H7.woff2 +0 -0
- data/public/index.html +2 -2
- data/public/{v0.12.0 → v0.13.0}/css/houseaccount.css +1 -1
- data/public/v0.13.0/font/bootstrap-icons-FRBPO3H7.woff2 +0 -0
- metadata +22 -19
- data/public/v0.12.0/font/bootstrap-icons-6LILWPE2.woff2 +0 -0
- /data/public/{v0.12.0 → v0.13.0}/font/quicksand-500-latin-QHYSRFVK.woff2 +0 -0
- /data/public/{v0.12.0 → v0.13.0}/font/quicksand-500-latin-ext-QZ4PXVHB.woff2 +0 -0
- /data/public/{v0.12.0 → v0.13.0}/font/quicksand-500-latin-ext.woff2 +0 -0
- /data/public/{v0.12.0 → v0.13.0}/font/quicksand-500-latin.woff2 +0 -0
- /data/public/{v0.12.0 → v0.13.0}/font/quicksand-500-vietnamese-RRA5CUQB.woff2 +0 -0
- /data/public/{v0.12.0 → v0.13.0}/font/quicksand-500-vietnamese.woff2 +0 -0
- /data/public/{v0.12.0 → v0.13.0}/js/houseaccount.js +0 -0
- /data/public/{v0.12.0 → v0.13.0}/theme/bootstrap.css +0 -0
- /data/public/{v0.12.0 → v0.13.0}/theme/dawn.css +0 -0
- /data/public/{v0.12.0 → v0.13.0}/theme/dracula.css +0 -0
- /data/public/{v0.12.0 → v0.13.0}/theme/gruvbox.css +0 -0
- /data/public/{v0.12.0 → v0.13.0}/theme/monokai.css +0 -0
- /data/public/{v0.12.0 → v0.13.0}/theme/nord.css +0 -0
- /data/public/{v0.12.0 → v0.13.0}/theme/one_dark.css +0 -0
- /data/public/{v0.12.0 → v0.13.0}/theme/solarized.css +0 -0
- /data/public/{v0.12.0 → v0.13.0}/theme/tokyo_night.css +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ed184a1937949b68eddec9963ca7432953697bcc370aa9831cc91c8fa5b19514
|
|
4
|
+
data.tar.gz: 570c5608351078cecfd03b7fb72a9601fce3897cfb30218eab31cd6c193b6ae7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a20b6800724be5cb32ff25b4f9de7f086b33e79dfdd09bf72cf3e03bd9189e7e26d6e2eb91894d2b3c8917ec3a405a5050e6a7124753e7d83cd8ab301047e03f
|
|
7
|
+
data.tar.gz: '0086d99c66d0b57cb7b6072b664b978a0d6d06394d8d95e550441c7c80d23773ca772f0a0b8c777dc01b484e9b57611d699f48fc25d90bdc84ecdcd840f28308'
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,29 @@ For more information about changelogs, check [Keep a Changelog](http://keepachan
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## 0.13.0 - 2026-09-17
|
|
11
|
+
|
|
12
|
+
* [Feature] The ascending sort glyph
|
|
13
|
+
|
|
14
|
+
`bi-sort-up` joins `bi-sort-down` in the subset. A table heading says which way its column
|
|
15
|
+
is sorted, and until now only one of the two directions had a glyph to say it with — the
|
|
16
|
+
other drew an empty box, since a name the subset does not carry has no `content` rule and
|
|
17
|
+
no code point in the font.
|
|
18
|
+
|
|
19
|
+
`unicon` names the pair as `:sort_asc` and `:sort_desc` from 3.7.0, which is where recourse
|
|
20
|
+
reads them from.
|
|
21
|
+
* [Change] The card is as wide as what it holds, and a page asking one question says `30rem`
|
|
22
|
+
* [Change] A legend wears nothing of ours
|
|
23
|
+
* [Change] A form of more than one field reads its rows from where their words start
|
|
24
|
+
* [Feature] `flow-middle` stands a card as tall as the rest and holds its content in the middle
|
|
25
|
+
* [Feature] The builder dresses every kind of field, so a page writes no Bootstrap class
|
|
26
|
+
* [Feature] `form.combobox` is a select the bundle searches, in the house's own words
|
|
27
|
+
* [Change] A fieldset carries its own spacing and the gap between its controls
|
|
28
|
+
* [Change] A rule inside the card is given room either side of it
|
|
29
|
+
* [Feature] `form.check` is a box and the words beside it, which no page draws by hand now
|
|
30
|
+
* [Feature] `form.label` with words and a block wraps the control, so a wide card takes two columns
|
|
31
|
+
* [Feature] `flow-scroll` gives any long card the height, the inner scroll and the fixed foot a chat's card has
|
|
32
|
+
|
|
10
33
|
## 0.12.0 - 2026-09-17
|
|
11
34
|
|
|
12
35
|
* [Change] The showcase shows rather than describes
|
data/README.md
CHANGED
|
@@ -186,6 +186,14 @@ as a template:
|
|
|
186
186
|
<%= render template: 'layouts/houseaccount' %>
|
|
187
187
|
```
|
|
188
188
|
|
|
189
|
+
A form's controls sit in `form.fieldset`, a grid, with a `legend` over them where a page has
|
|
190
|
+
one; `form.label` given both its words and a block wraps the control those words name, which is
|
|
191
|
+
the cell a card wide enough for two columns lays out. Every kind of field is dressed by the
|
|
192
|
+
builder rather than by the page — a number, a menu, a box that is ticked — so a view names the
|
|
193
|
+
kind it wants and no class at all, and `form.combobox` is a menu the bundle searches, given the
|
|
194
|
+
words it says before a pick. Everything else in the fieldset keeps the whole row, and
|
|
195
|
+
the card is what is measured rather than the window, so a narrow one stays in one column.
|
|
196
|
+
|
|
189
197
|
`content_for :logo` is which of the family's marks the tab wears, for a page a customer reads
|
|
190
198
|
rather than the app's own people: unsaid, it is this app's, by its name.
|
|
191
199
|
|
data/art/icons.txt
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
en:
|
|
2
2
|
houseaccount:
|
|
3
3
|
ago: '%{time} ago'
|
|
4
|
+
all: All
|
|
4
5
|
ask: Ask a question
|
|
6
|
+
clear: Clear
|
|
5
7
|
close: Close
|
|
8
|
+
more: '%{first} + %{count} more'
|
|
9
|
+
no_results: Nothing matches that
|
|
6
10
|
okay: Okay
|
|
7
11
|
one_time_code: |-
|
|
8
12
|
Enter this 6-digit code to proceed: %{pin}
|
|
9
13
|
|
|
10
14
|
@%{host} #%{pin}
|
|
15
|
+
search: Search
|
|
11
16
|
send: Send
|
|
12
17
|
spoken_one_time_code: 'Enter this 6-digit code to proceed: %{pin}'
|
|
13
18
|
typing: Typing
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'action_view'
|
|
2
|
+
|
|
3
|
+
module HouseAccount
|
|
4
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
|
5
|
+
# The menu the bundle draws as a combobox: Bootstrap's toggle and a searchable menu built
|
|
6
|
+
# from a select it then hides, which stays the one thing the form submits.
|
|
7
|
+
module Comboboxes
|
|
8
|
+
# The words the menu is read by, which belong to the house rather than to a page.
|
|
9
|
+
WORDS = %i[all clear more no_results search].freeze
|
|
10
|
+
|
|
11
|
+
# `method` as a combobox over `choices` -- the select `form.select` would draw, carrying
|
|
12
|
+
# what the bundle needs to draw it as one instead. Every argument is that select's, and
|
|
13
|
+
# its own `:prompt` is what the toggle says before anything is picked. The words it is
|
|
14
|
+
# searched, cleared and emptied by are the house's, in the reader's own language, and
|
|
15
|
+
# `data` given in `html_options` is kept over any of them.
|
|
16
|
+
def combobox(method, choices = nil, options = {}, html_options = {}, &)
|
|
17
|
+
data = { controller: 'combobox', combobox_placeholder_value: options[:prompt],
|
|
18
|
+
**houseaccount_combobox_words, **html_options.fetch(:data, {}), }
|
|
19
|
+
|
|
20
|
+
select method, choices, options, html_options.merge(data: data), &
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
# `all` and `more` are Stimulus values the menu reads; the rest are plain attributes.
|
|
26
|
+
# `more` is a template the bundle fills, so it is asked for with its own placeholders as
|
|
27
|
+
# their values -- I18n would otherwise raise on the two it cannot fill.
|
|
28
|
+
def houseaccount_combobox_words
|
|
29
|
+
WORDS.to_h do |word|
|
|
30
|
+
# rubocop:disable-next Style/FormatStringToken -- the bundle fills these, not Ruby
|
|
31
|
+
said = @template.t "houseaccount.#{word}", first: '%{first}', count: '%{count}'
|
|
32
|
+
|
|
33
|
+
[%i[all more].include?(word) ? :"combobox_#{word}_value" : word, said]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
require 'action_view'
|
|
2
|
+
|
|
3
|
+
module HouseAccount
|
|
4
|
+
class FormBuilder < ActionView::Helpers::FormBuilder
|
|
5
|
+
# Every other kind of field, at the one size the house draws them: a page says which kind
|
|
6
|
+
# it wants and nothing about how it looks. Rails hands an undressed control to whatever it
|
|
7
|
+
# has no method for here, which is how a Bootstrap class ends up written in a view.
|
|
8
|
+
module Controls
|
|
9
|
+
# What a menu wears: the control's size, so a menu and a box beside it line up.
|
|
10
|
+
MENU = 'form-select form-select-lg'
|
|
11
|
+
|
|
12
|
+
# What a box or a circle that is ticked wears.
|
|
13
|
+
CHECK = 'form-check-input'
|
|
14
|
+
|
|
15
|
+
# An email address.
|
|
16
|
+
def email_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
17
|
+
|
|
18
|
+
# A number, which brings the keyboard for one.
|
|
19
|
+
def number_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
20
|
+
|
|
21
|
+
# A password, which no name of a column earns on its own.
|
|
22
|
+
def password_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
23
|
+
|
|
24
|
+
# A term to search by.
|
|
25
|
+
def search_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
26
|
+
|
|
27
|
+
# A web address.
|
|
28
|
+
def url_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
29
|
+
|
|
30
|
+
# A day.
|
|
31
|
+
def date_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
32
|
+
|
|
33
|
+
# A time of day.
|
|
34
|
+
def time_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
35
|
+
|
|
36
|
+
# A day and a time together.
|
|
37
|
+
def datetime_field(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
38
|
+
|
|
39
|
+
# More than a line of words.
|
|
40
|
+
def text_area(method, options = {}) = super(method, with_classes(options, CONTROL))
|
|
41
|
+
|
|
42
|
+
# A menu of what a column may be.
|
|
43
|
+
def select(method, choices = nil, options = {}, html_options = {}, &)
|
|
44
|
+
super(method, choices, options, with_classes(html_options, MENU), &)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# One of several, ticked.
|
|
48
|
+
def check_box(method, options = {}, checked = '1', unchecked = '0')
|
|
49
|
+
super(method, with_classes(options, CHECK), checked, unchecked)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# One of several, and only one.
|
|
53
|
+
def radio_button(method, value, options = {})
|
|
54
|
+
super(method, value, with_classes(options, CHECK))
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# A box and the words beside it, which is the one place words sit after a control rather
|
|
58
|
+
# than over it -- so they are not the label a field wears, and are written here instead.
|
|
59
|
+
def check(method, text, options = {})
|
|
60
|
+
words = @template.label_tag field_id(method), text, class: 'form-check-label'
|
|
61
|
+
inside = @template.safe_join [check_box(method, options), words]
|
|
62
|
+
|
|
63
|
+
@template.tag.div inside, class: 'form-check'
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
require 'action_view'
|
|
2
|
+
require_relative 'form_builder/comboboxes'
|
|
3
|
+
require_relative 'form_builder/controls'
|
|
2
4
|
require_relative 'form_builder/pins'
|
|
3
5
|
|
|
4
6
|
module HouseAccount
|
|
@@ -7,7 +9,7 @@ module HouseAccount
|
|
|
7
9
|
# `default_form_builder`. What a view passes is kept: its classes join the house's, its
|
|
8
10
|
# `data` is merged key by key with the house's, and any other option of its overrides.
|
|
9
11
|
class FormBuilder < ActionView::Helpers::FormBuilder
|
|
10
|
-
include Pins
|
|
12
|
+
include Comboboxes, Controls, Pins
|
|
11
13
|
|
|
12
14
|
# What a field wears: Bootstrap's control, at the size a thumb finds.
|
|
13
15
|
CONTROL = 'form-control form-control-lg'
|
|
@@ -25,21 +27,31 @@ module HouseAccount
|
|
|
25
27
|
data: { controller: 'phone', action: 'keydown->phone#down input->phone#input' },
|
|
26
28
|
}.freeze
|
|
27
29
|
|
|
28
|
-
# The fieldset a form's controls sit in: a grid
|
|
29
|
-
#
|
|
30
|
-
#
|
|
30
|
+
# The fieldset a form's controls sit in: a grid, with `legend` over them where one is
|
|
31
|
+
# given, wearing nothing of ours. It carries
|
|
32
|
+
# its own spacing, twice as much under it as over, so one group reads as belonging to the
|
|
33
|
+
# words above it rather than sitting evenly between two. Every option is the fieldset's.
|
|
31
34
|
def fieldset(legend = nil, **options, &)
|
|
32
|
-
heading = (@template.tag.legend legend
|
|
35
|
+
heading = (@template.tag.legend legend if legend)
|
|
33
36
|
inside = @template.safe_join [heading, @template.capture(&)].compact
|
|
34
37
|
|
|
35
|
-
@template.tag.fieldset inside, **with_classes(options, 'd-grid')
|
|
38
|
+
@template.tag.fieldset inside, **with_classes(options, 'd-grid form-fieldset')
|
|
36
39
|
end
|
|
37
40
|
|
|
38
|
-
# A label is Bootstrap's `form-label`, whatever else it is given
|
|
39
|
-
|
|
40
|
-
|
|
41
|
+
# A label is Bootstrap's `form-label`, whatever else it is given -- and given both words
|
|
42
|
+
# and a block, the control the words name as well, which Rails' own label has no meaning
|
|
43
|
+
# for: it drops the words and renders the block. Wrapped, the pair is one element, so a
|
|
44
|
+
# form laid out in columns has a cell to place and neither an id nor a stylesheet counting
|
|
45
|
+
# children has to bind them -- which a control drawing markup of its own, a combobox say,
|
|
46
|
+
# would break on connect.
|
|
47
|
+
def label(method, text = nil, options = {}, &block)
|
|
48
|
+
return label(method, nil, text, &block) if text.is_a? Hash
|
|
49
|
+
return super(method, text, with_classes(options, 'form-label'), &block) unless text && block
|
|
41
50
|
|
|
42
|
-
|
|
51
|
+
words = @template.tag.span text, class: 'form-label'
|
|
52
|
+
inside = @template.safe_join [words, @template.capture(&block)]
|
|
53
|
+
|
|
54
|
+
@template.tag.label inside, for: field_id(method), **with_classes(options, 'form-field')
|
|
43
55
|
end
|
|
44
56
|
|
|
45
57
|
# A text field is a large control.
|
data/lib/houseaccount/version.rb
CHANGED