bh 6.3.0 → 6.5.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 +27 -0
- data/app/stylesheets/bh/chat.css +27 -0
- data/app/stylesheets/bh/shell.css +7 -1
- data/config/locales/bh.en.yml +1 -0
- data/lib/bh/helpers/chats.rb +32 -5
- data/lib/bh/message.rb +10 -7
- data/lib/bh/version.rb +1 -1
- data/package.json +1 -1
- data/public/bh/css/bh.css +1 -1
- 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: bcf981e1ac2ccf3453876292551f8c226f128d580df804e5fe639bfa93cd891e
|
|
4
|
+
data.tar.gz: 493f3eed784399be33e0d1a96ac3152dbb44ab6da23539e4f596ec6e26419bd0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dee9ed53e3555c3643795bbbd2d6edf0079fb018fb72eb070bfa94f6eefe1bccb177db45dcb94bbbfa3a9702b04217222203a5757aa7877b443a4efc229f84c5
|
|
7
|
+
data.tar.gz: 4d12abc38791cff92dc944a0626333fa269bfc6e2b012b7787329ee31445b445c7fb7b6a79f658e119cc28037ea82de71914155cbba0f6c085a35edfd0ebf9da
|
data/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,33 @@ For more information about changelogs, check
|
|
|
8
8
|
|
|
9
9
|
## [Unreleased]
|
|
10
10
|
|
|
11
|
+
## 6.5.0 - 2026-09-18
|
|
12
|
+
|
|
13
|
+
* [FIX] The shell fills the screen in whole pixels
|
|
14
|
+
|
|
15
|
+
`100dvh` computes to a fraction on a scaled display -- 415.455px against a viewport
|
|
16
|
+
reporting 415 -- and the tenths over are enough for a browser to draw a scrollbar the
|
|
17
|
+
page cannot use, beside the one the content it holds already has. The shell takes a
|
|
18
|
+
percentage of a document given a height instead, which is the same whole number the
|
|
19
|
+
viewport reports.
|
|
20
|
+
|
|
21
|
+
## 6.4.0 - 2026-09-18
|
|
22
|
+
|
|
23
|
+
* [FEATURE] A message carries its `photos`, drawn in the bubble under its words
|
|
24
|
+
|
|
25
|
+
`Bh::Message` takes a list of addresses beside its text. Each is drawn under the words in
|
|
26
|
+
the same bubble, linking to itself in a tab of its own: what fits beside words is rarely
|
|
27
|
+
what somebody wants to look at. A message carrying pictures and no words is a message all
|
|
28
|
+
the same, rather than one still being typed.
|
|
29
|
+
|
|
30
|
+
* [FEATURE] `chat_with` takes a `note:`, said over the thread rather than in it
|
|
31
|
+
|
|
32
|
+
What the conversation is about, or the other way to reach whoever is on the far end of it.
|
|
33
|
+
Over rather than in, because nobody in the conversation said it and a bubble would claim
|
|
34
|
+
somebody had. It holds the top while the thread scrolls under it, and carries the page's
|
|
35
|
+
own background for that reason: a tint would read as somebody's turn, and without one the
|
|
36
|
+
bubbles would show through.
|
|
37
|
+
|
|
11
38
|
## 6.3.0 - 2026-09-18
|
|
12
39
|
|
|
13
40
|
* [FEATURE] The nine palettes, served at `/bh/theme/<name>.css`
|
data/app/stylesheets/bh/chat.css
CHANGED
|
@@ -7,6 +7,33 @@
|
|
|
7
7
|
overflows pushes its first message clean out of the top with no way to scroll back. */
|
|
8
8
|
.chat > :first-child { margin-block-start: auto }
|
|
9
9
|
|
|
10
|
+
/* What the whole thread is about, or the other way to reach whoever is on the far end of
|
|
11
|
+
it: said over the conversation rather than in it, quiet and in the page's own words,
|
|
12
|
+
because nobody in the conversation said it. It holds the top while the thread scrolls
|
|
13
|
+
under it, which is why it carries the page's background and not a band of its own: a
|
|
14
|
+
tint here would read as somebody's turn, and bubbles would show through without one. */
|
|
15
|
+
.chat-note {
|
|
16
|
+
position: sticky;
|
|
17
|
+
inset-block-start: 0;
|
|
18
|
+
z-index: 1;
|
|
19
|
+
background-color: var(--bs-body-bg);
|
|
20
|
+
font-size: var(--bs-font-size-sm);
|
|
21
|
+
color: var(--bs-fg-2);
|
|
22
|
+
margin: 0;
|
|
23
|
+
padding-block: 0.25rem 0.75rem;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* A picture a message carries, under its words and no wider than the bubble holding it. */
|
|
27
|
+
.chat-photo {
|
|
28
|
+
display: block;
|
|
29
|
+
max-width: 100%;
|
|
30
|
+
height: auto;
|
|
31
|
+
border-radius: 0.5rem;
|
|
32
|
+
margin-block-start: 0.5rem;
|
|
33
|
+
}
|
|
34
|
+
/* The first thing in a bubble has the bubble's own padding over it already. */
|
|
35
|
+
.chat-bubble > a:first-child .chat-photo { margin-block-start: 0 }
|
|
36
|
+
|
|
10
37
|
/* Who said it and when, small, over the bubble it belongs to and on its side. */
|
|
11
38
|
.chat-aside { font-size: var(--bs-font-size-sm); color: var(--bs-fg-2); margin: 0 0.75rem }
|
|
12
39
|
.chat-aside-out { align-self: flex-end; margin-inline-end: 1.25rem }
|
|
@@ -21,6 +21,9 @@ span.breadcrumb-link.active {
|
|
|
21
21
|
page whose table had no rows to be taller than the menu. `clip` leaves the
|
|
22
22
|
other axis alone. */
|
|
23
23
|
html { overflow-x: hidden; }
|
|
24
|
+
/* And a height for the shell below to take a percentage of, so the one screen it
|
|
25
|
+
fills is measured in whole pixels rather than in a unit that carries a fraction. */
|
|
26
|
+
html, body { height: 100%; }
|
|
24
27
|
.recourse-shell { overflow-x: clip; }
|
|
25
28
|
|
|
26
29
|
/* A finger does not hover. The tint a pointer leaves on the row under it, or on
|
|
@@ -65,7 +68,10 @@ html { overflow-x: hidden; }
|
|
|
65
68
|
grid-template-columns: auto minmax(0, 1fr);
|
|
66
69
|
grid-template-rows: auto minmax(0, 1fr);
|
|
67
70
|
grid-template-areas: 'nav nav' 'aside main';
|
|
68
|
-
|
|
71
|
+
/* A percentage of the block a viewport unit would have measured: `100dvh` carries
|
|
72
|
+
the fraction a scaled display computes it to -- 415.455px against a viewport
|
|
73
|
+
reporting 415 -- and the tenths over are a scrollbar the page cannot use. */
|
|
74
|
+
height: 100%;
|
|
69
75
|
}
|
|
70
76
|
.recourse-shell > nav { grid-area: nav; }
|
|
71
77
|
.recourse-sidebar { grid-area: aside; }
|
data/config/locales/bh.en.yml
CHANGED
data/lib/bh/helpers/chats.rb
CHANGED
|
@@ -8,12 +8,16 @@ module Bh
|
|
|
8
8
|
include Asides, Asks
|
|
9
9
|
|
|
10
10
|
# `messages` as a thread that opens at its newest and, where `url` is given, a field
|
|
11
|
-
# under it that posts the next message there, suggesting `hints` one at a time.
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
# under it that posts the next message there, suggesting `hints` one at a time. A
|
|
12
|
+
# `note` stands over the whole thread: what this conversation is about, or the other
|
|
13
|
+
# way to reach whoever is on the far end of it.
|
|
14
|
+
def chat_with(messages:, url: nil, hints: [], note: nil)
|
|
15
|
+
parts = [bh_chat_note(note), bh_chat_messages(messages)]
|
|
14
16
|
parts.push bh_chat_ask(url, hints) if url
|
|
15
17
|
|
|
16
|
-
|
|
18
|
+
said = safe_join parts.compact, "\n"
|
|
19
|
+
|
|
20
|
+
tag.div said, class: 'chat-thread', data: { controller: 'thread' }
|
|
17
21
|
end
|
|
18
22
|
|
|
19
23
|
private
|
|
@@ -30,13 +34,36 @@ module Bh
|
|
|
30
34
|
safe_join parts.compact, "\n"
|
|
31
35
|
end
|
|
32
36
|
|
|
37
|
+
# Said over the thread rather than in it, so it is not one of the turns: nobody
|
|
38
|
+
# said this, and a bubble would claim somebody had.
|
|
39
|
+
def bh_chat_note(note)
|
|
40
|
+
tag.p note, class: 'chat-note' if note.present?
|
|
41
|
+
end
|
|
42
|
+
|
|
33
43
|
def bh_chat_bubble(message)
|
|
34
44
|
side = Asides::SIDES.fetch message.side
|
|
35
|
-
|
|
45
|
+
said = bh_chat_said message
|
|
46
|
+
return tag.p said, class: "chat-bubble chat-#{side}" if said
|
|
36
47
|
|
|
37
48
|
tag.p safe_join(Array.new(3) { tag.span }), class: "chat-bubble chat-#{side} chat-typing",
|
|
38
49
|
aria: { label: t('bh.typing') }
|
|
39
50
|
end
|
|
51
|
+
|
|
52
|
+
# The words and then the pictures, which is the order a phone lays a picture
|
|
53
|
+
# message out in -- and nothing at all where a message has neither yet.
|
|
54
|
+
def bh_chat_said(message)
|
|
55
|
+
pictures = Array(message.photos).map { |photo| bh_chat_photo photo }
|
|
56
|
+
|
|
57
|
+
safe_join([message.text, *pictures].compact_blank, "\n").presence
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# A picture in the bubble, opening full size in a tab of its own: what fits beside
|
|
61
|
+
# words is rarely what somebody wants to look at.
|
|
62
|
+
def bh_chat_photo(url)
|
|
63
|
+
tag.a href: url, target: :_blank, rel: 'noopener' do
|
|
64
|
+
tag.img src: url, alt: t('bh.photo'), class: 'chat-photo', loading: :lazy
|
|
65
|
+
end
|
|
66
|
+
end
|
|
40
67
|
end
|
|
41
68
|
end
|
|
42
69
|
end
|
data/lib/bh/message.rb
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
module Bh
|
|
2
2
|
# One message of a chat, as `chat_with` draws it: which `side` its bubble is on (`:left`
|
|
3
|
-
# for the other party, `:right` for the reader), its `text`,
|
|
4
|
-
# was said (`at`), how its `delivery`
|
|
5
|
-
# `:undelivered` or nil) and what it `cost` in
|
|
6
|
-
# answering the same
|
|
7
|
-
# model to hang them on. A message with
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
# for the other party, `:right` for the reader), its `text`, the `photos` it carries as
|
|
4
|
+
# a list of addresses, who the `sender` was, when it was said (`at`), how its `delivery`
|
|
5
|
+
# went (`:delivered`, `:sent`, `:failed`, `:undelivered` or nil) and what it `cost` in
|
|
6
|
+
# dollars, where anything did. Any object answering the same seven is a message too;
|
|
7
|
+
# this is for a host that has the facts and no model to hang them on. A message with
|
|
8
|
+
# neither words nor pictures yet is drawn as being typed.
|
|
9
|
+
Message = Data.define :side, :text, :photos, :sender, :at, :delivery, :cost do
|
|
10
|
+
def initialize(side:, text: nil, photos: [], sender: nil, at: nil, delivery: nil, cost: nil)
|
|
11
|
+
super
|
|
12
|
+
end
|
|
10
13
|
end
|
|
11
14
|
end
|
data/lib/bh/version.rb
CHANGED
data/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bh6",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.5.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"description": "Bootstrap 6 in a Rails app: the form builder that dresses every field, the components Bootstrap ships behavior for and no markup, and the Stimulus controllers behind them.",
|
|
6
6
|
"license": "MIT",
|