tramway 3.0.3.3 → 3.0.4

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: 17fe97e6ab94f2d72d4cb67fad3facfafa3d2e9e046e9a52b84bc376beddd3f2
4
- data.tar.gz: 1d3ba244c662e9facdd4a2f28c63c4a20bfb720295fca5713e7eb633cf1ff696
3
+ metadata.gz: 8f1294b704f5b6bc2779d6eae4168a9c63508af6b485dfe267fa70a1b2ca786e
4
+ data.tar.gz: 662bf3c75f819a46229a55cce0804b11a70511ade1ecbc08e8aa50a09d246381
5
5
  SHA512:
6
- metadata.gz: 745193d204d4e871248c8bc7531dd5d74b9c99759cc45d5190ed1f66ffca3b109d82239154aa86cfd70804c15c1683f848b92adbd20a43d3bdddc102a2c9b7d2
7
- data.tar.gz: d14350608083e3dc4ab6d0c4de6bd7e057a45c9d289c0fdff37080e0e365b4d265f734647cfe296afbc1356c1dcf0ea1c7ef3258265206f588b85f3e90f2f6ad
6
+ metadata.gz: 90eb4ab0b7d5e871f904d320a42469ea92d35a83ebad3c014b167fe7b5294e7c046c1c0ebc41f64a09693794995e82641d69b3cb9d59d3e5183f5108ace44745
7
+ data.tar.gz: 53bc0d610787669587ed26f4c6bbadce0c0e476ae34b8f4ea49128ad7e20265080d09abdf3726fea93aea1014a2a935b12077b6049c47fd46c199c044ad6872f
data/README.md CHANGED
@@ -925,17 +925,17 @@ When set to `false`, the text field is disabled and the waiting placeholder is s
925
925
  If you do not want to render the message form, pass `message_form: nil`. When the form is present, `send_message_path` is
926
926
  required and the helper will generate the correct POST form.
927
927
 
928
- To append messages to an already-rendered `tramway_chat` stream, use `tramway_chat_append_message`.
928
+ To append a message to an already-rendered `tramway_chat` stream, use `tramway_chat_append_message`.
929
929
  The method is mixed into controllers and ActiveRecord models by Tramway and expects:
930
930
  - `chat_id:` — the same value used in `tramway_chat chat_id:`
931
- - `message_type:` — only `:sent` or `:received` (raises `ArgumentError` otherwise)
931
+ - `type:` — only `:sent` or `:received` (raises `ArgumentError` otherwise)
932
932
  - `text:` — message content
933
933
  - `sent_at:` — message timestamp
934
934
 
935
935
  ```ruby
936
936
  tramway_chat_append_message(
937
937
  chat_id: 'support-chat',
938
- message_type: :received,
938
+ type: :received,
939
939
  text: 'We got your request',
940
940
  sent_at: Time.current
941
941
  )
@@ -943,6 +943,49 @@ tramway_chat_append_message(
943
943
 
944
944
  It broadcasts with `target: 'messages'` and renders the `tramway/chats/message` partial so the message appears in the live chat.
945
945
 
946
+ To prepend a message to the same stream, use `tramway_chat_prepend_message`. It accepts the same arguments and validation rules,
947
+ but inserts the rendered `tramway/chats/message` partial at the beginning of the `messages` target instead of the end.
948
+
949
+ ```ruby
950
+ tramway_chat_prepend_message(
951
+ chat_id: 'support-chat',
952
+ type: :received,
953
+ text: 'Earlier message from history',
954
+ sent_at: 5.minutes.ago
955
+ )
956
+ ```
957
+
958
+ To append multiple messages at once, use `tramway_chat_append_messages`. The method expects:
959
+ - `chat_id:` — the same value used in `tramway_chat chat_id:`
960
+ - `messages:` — an array of hashes, where each hash includes `type:`, `text:`, and `sent_at:`
961
+
962
+ Each message `type:` must be `:sent` or `:received` or the helper raises `ArgumentError`. It broadcasts with `target:
963
+ 'messages'` and renders the `tramway/chats/messages` partial so the full collection appears in the live chat.
964
+
965
+ ```ruby
966
+ tramway_chat_append_messages(
967
+ chat_id: 'support-chat',
968
+ messages: [
969
+ { type: :received, text: 'First update', sent_at: 2.minutes.ago },
970
+ { type: :sent, text: 'Thanks, checking now', sent_at: 1.minute.ago }
971
+ ]
972
+ )
973
+ ```
974
+
975
+ To prepend multiple messages, use `tramway_chat_prepend_messages`. It accepts the same `chat_id:` and `messages:` arguments
976
+ as `tramway_chat_append_messages`, validates each `type:`, and prepends the rendered `tramway/chats/messages` partial to the
977
+ beginning of the `messages` target.
978
+
979
+ ```ruby
980
+ tramway_chat_prepend_messages(
981
+ chat_id: 'support-chat',
982
+ messages: [
983
+ { type: :received, text: 'Older history item', sent_at: 10.minutes.ago },
984
+ { type: :sent, text: 'Reply from earlier', sent_at: 9.minutes.ago }
985
+ ]
986
+ )
987
+ ```
988
+
946
989
  ### Tramway Table Component
947
990
 
948
991
  Tramway provides a responsive, tailwind-styled table with light and dark themes. Use the `tramway_table`, `tramway_row`, and
@@ -1,7 +1,7 @@
1
1
  = helpers.turbo_stream_from chat_id, 'messages'
2
2
 
3
3
  #chat.flex.flex-1.h-full.w-full.min-h-0.min-w-0.flex-col
4
- #messages.flex.flex-col.flex-1.min-h-0.overflow-y-auto.overflow-x-hidden.p-2.md:p-6.space-y-2.md:space-y-4.md:rounded-xl.rounded-t-xl{ class: 'text-gray-100 bg-gray-800/60' }
4
+ #messages.flex.flex-col.flex-1.min-h-0.overflow-y-auto.overflow-x-hidden.p-2.md:p-6.space-y-2.md:space-y-4.md:rounded-xl.rounded-t-xl{ class: 'text-gray-100 bg-gray-800/60', data: { scroll_to_bottom_on_update: scroll_to_bottom_on_update } }
5
5
  - messages.each do |message|
6
6
  = component "tramway/chats/message", **message
7
7
  - if disabled?
@@ -31,13 +31,23 @@
31
31
  const messages = document.getElementById('messages');
32
32
  if (!messages || messages.dataset.chatScrollInitialized === 'true') return;
33
33
 
34
+ const shouldScrollToBottomOnUpdate = () => {
35
+ return messages.dataset.scrollToBottomOnUpdate !== 'false' &&
36
+ messages.dataset.preserveScroll !== 'true';
37
+ };
38
+
34
39
  const scrollToBottom = () => {
35
40
  messages.scrollTop = messages.scrollHeight;
36
41
  };
37
42
 
43
+ // Always scroll to bottom on initial page load.
38
44
  scrollToBottom();
39
45
 
40
- const observer = new MutationObserver(scrollToBottom);
46
+ const observer = new MutationObserver(() => {
47
+ if (!shouldScrollToBottomOnUpdate()) return;
48
+ scrollToBottom();
49
+ });
50
+
41
51
  observer.observe(messages, { childList: true });
42
52
 
43
53
  messages.dataset.chatScrollInitialized = 'true';
@@ -9,6 +9,7 @@ module Tramway
9
9
  option :options, optional: true, default: -> { {} }
10
10
  option :send_message_path
11
11
  option :send_messages_enabled, optional: true, default: -> { true }
12
+ option :scroll_to_bottom_on_update, optional: true, default: -> { true }
12
13
 
13
14
  def disabled?
14
15
  options[:disabled]
@@ -1,2 +1,2 @@
1
- %main.w-full.min-h-dvh{ class: container_classes }
1
+ %main.w-full.min-h-dvh{ class: container_classes, **options.except(:class) }
2
2
  = content
@@ -4,9 +4,13 @@ module Tramway
4
4
  module Containers
5
5
  # Main container for tailwind-styled layout
6
6
  class MainComponent < Tramway::BaseComponent
7
+ option :options, optional: true, default: proc { {} }
8
+
7
9
  def container_classes
10
+ options_classes = options[:class] || ''
11
+
8
12
  theme_classes(
9
- classic: 'bg-gray-900 text-gray-100 shadow-inner'
13
+ classic: "bg-gray-900 text-gray-100 shadow-inner#{options_classes}"
10
14
  )
11
15
  end
12
16
  end
@@ -1,3 +1,3 @@
1
- %div{ class: container_classes, id:, **options }
1
+ %div{ class: container_classes, id:, **options.except(:class, :id) }
2
2
  .flex.flex-col.justify-center.w-full
3
3
  = content
@@ -8,9 +8,11 @@ module Tramway
8
8
  option :options, optional: true, default: proc { {} }
9
9
 
10
10
  def container_classes
11
+ options_classes = options[:class] || ''
12
+
11
13
  theme_classes(
12
14
  classic: 'container p-4 flex align-center justify-center w-full mx-auto bg-gray-100 text-gray-700 ' \
13
- 'shadow-inner rounded-xl bg-gray-900 text-gray-100'
15
+ 'shadow-inner rounded-xl bg-gray-900 text-gray-100' + options_classes
14
16
  )
15
17
  end
16
18
  end
@@ -1,4 +1 @@
1
- = component 'tramway/chats/message',
2
- type:,
3
- text:,
4
- sent_at:
1
+ = component 'tramway/chats/message', type:, text:, sent_at:
@@ -0,0 +1,2 @@
1
+ - messages.each do |message|
2
+ = component 'tramway/chats/message', type:, text:, sent_at:
@@ -91,7 +91,7 @@ module Tramway
91
91
  end
92
92
 
93
93
  def agents_template_url
94
- 'https://github.com/Purple-Magic/base_project/blob/main/docs/agents/tramway.md'
94
+ 'https://raw.githubusercontent.com/Purple-Magic/tramway-skill/refs/heads/main/skills/tramway-skill/agents/tramway.md'
95
95
  end
96
96
 
97
97
  def agents_template_body
@@ -14,6 +14,43 @@ module Tramway
14
14
  partial: 'tramway/chats/message',
15
15
  locals: { type:, text:, sent_at: }
16
16
  end
17
+
18
+ def tramway_chat_prepend_message(chat_id:, type:, text:, sent_at:)
19
+ raise ArgumentError, 'message_type must be :sent or :received' unless MESSAGE_TYPES.include?(type.to_sym)
20
+
21
+ Turbo::StreamsChannel.broadcast_prepend_to [chat_id, 'messages'],
22
+ target: 'messages',
23
+ partial: 'tramway/chats/message',
24
+ locals: { type:, text:, sent_at: }
25
+ end
26
+
27
+ def tramway_chat_append_messages(chat_id:, messages:)
28
+ messages.each do |message|
29
+ unless MESSAGE_TYPES.include?(message[:type].to_sym)
30
+ raise ArgumentError,
31
+ 'Each message must have :id and :type keys'
32
+ end
33
+ end
34
+
35
+ Turbo::StreamsChannel.broadcast_append_to [chat_id, 'messages'],
36
+ target: 'messages',
37
+ partial: 'tramway/chats/messages',
38
+ locals: { messages: }
39
+ end
40
+
41
+ def tramway_chat_prepend_messages(chat_id:, messages:)
42
+ messages.each do |message|
43
+ unless MESSAGE_TYPES.include?(message[:type].to_sym)
44
+ raise ArgumentError,
45
+ 'Each message must have :id and :type keys'
46
+ end
47
+ end
48
+
49
+ Turbo::StreamsChannel.broadcast_prepend_to [chat_id, 'messages'],
50
+ target: 'messages',
51
+ partial: 'tramway/chats/messages',
52
+ locals: { messages: }
53
+ end
17
54
  end
18
55
  end
19
56
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tramway
4
- VERSION = '3.0.3.3'
4
+ VERSION = '3.0.4'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tramway
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.3.3
4
+ version: 3.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - kalashnikovisme
@@ -250,6 +250,7 @@ files:
250
250
  - app/views/kaminari/_paginator.html.haml
251
251
  - app/views/kaminari/_prev_page.html.haml
252
252
  - app/views/tramway/chats/_message.html.haml
253
+ - app/views/tramway/chats/_messages.html.haml
253
254
  - app/views/tramway/entities/_form.html.haml
254
255
  - app/views/tramway/entities/_list.html.haml
255
256
  - app/views/tramway/entities/edit.html.haml