tramway 3.0.4.2 → 3.1

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -9
  3. data/app/assets/javascripts/tramway/ui_checkbox_controller.js +36 -0
  4. data/app/components/tailwind_component.rb +21 -24
  5. data/app/components/tramway/button_component.rb +33 -21
  6. data/app/components/tramway/chat_component.html.haml +6 -6
  7. data/app/components/tramway/chats/message_component.html.haml +2 -2
  8. data/app/components/tramway/chats/message_component.rb +2 -2
  9. data/app/components/tramway/chats/messages/container_component.html.haml +3 -3
  10. data/app/components/tramway/chats/messages/container_component.rb +4 -9
  11. data/app/components/tramway/chats/messages/table_component.html.haml +1 -1
  12. data/app/components/tramway/colors_methods.rb +3 -3
  13. data/app/components/tramway/containers/main_component.rb +1 -1
  14. data/app/components/tramway/containers/narrow_component.rb +2 -2
  15. data/app/components/tramway/flash_component.html.haml +0 -1
  16. data/app/components/tramway/flash_component.rb +25 -10
  17. data/app/components/tramway/form/builder.rb +1 -1
  18. data/app/components/tramway/form/checkbox_component.html.haml +26 -4
  19. data/app/components/tramway/form/checkbox_component.rb +32 -1
  20. data/app/components/tramway/form/label_component.html.haml +1 -1
  21. data/app/components/tramway/form/label_component.rb +2 -3
  22. data/app/components/tramway/form/tramway_select/dropdown_container_component.rb +2 -5
  23. data/app/components/tramway/form/tramway_select/item_container_component.rb +1 -3
  24. data/app/components/tramway/form/tramway_select/select_as_input_component.rb +1 -4
  25. data/app/components/tramway/form/tramway_select/selected_item_template_component.rb +4 -4
  26. data/app/components/tramway/nav/item_component.rb +2 -5
  27. data/app/components/tramway/navbar_component.html.haml +6 -6
  28. data/app/components/tramway/navbar_component.rb +19 -15
  29. data/app/components/tramway/pagination/base.rb +6 -6
  30. data/app/components/tramway/pagination/gap_component.rb +1 -3
  31. data/app/components/tramway/pagination/page_component.rb +2 -3
  32. data/app/components/tramway/table/cell_component.rb +1 -3
  33. data/app/components/tramway/table/header_component.html.haml +1 -1
  34. data/app/components/tramway/table/header_component.rb +2 -4
  35. data/app/components/tramway/table/row_component.html.haml +1 -1
  36. data/app/components/tramway/table/row_component.rb +7 -12
  37. data/app/components/tramway/table_component.rb +1 -3
  38. data/app/views/tramway/entities/_form.html.haml +1 -2
  39. data/app/views/tramway/layouts/application.html.haml +1 -1
  40. data/config/tailwind.config.js +278 -70
  41. data/lib/generators/tramway/install/install_generator.rb +44 -4
  42. data/lib/tramway/engine.rb +1 -1
  43. data/lib/tramway/version.rb +1 -1
  44. metadata +2 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6df450ba2be14dca796231458310c25cbbc33d51d39de0bbeb7af4d8c0fadba1
4
- data.tar.gz: 26ded3945beb84b04c0ea7c7916a3a8b1bc9beb14e7df7886a8add7d1bebb983
3
+ metadata.gz: 8d6347854d4ed5eb627a0adb496c8f6ffd7d5f5d4948c510586af26f42bc7a3f
4
+ data.tar.gz: 52d08842b5fd4a6cb025d23e5faf8de44b699e4ed471b8c24049955bfab1a93f
5
5
  SHA512:
6
- metadata.gz: 350d5eaf8eb2aadc8b458bc9834340ee34efe36ce4dbec2960214331b89e6979329b1c61c607b7cf64b595fb7c81e62959144d78708755c2e8964872f0f89dd2
7
- data.tar.gz: 1d7215149e091f8b967fbee6471d68a77c90f57294022f66327626e300759ad31f01d4e30e019c1a17f571e7adba9f09f404089f0960bd129fc1c4918f0c86b7
6
+ metadata.gz: b92182b455ad051e1e08e7020674ff3079acb09afba3e6845ad53b284cdf3fbe6844855b1b948a9066a990e3d669833a70d1cac04b62c15bf6fca22b27b0cbb9
7
+ data.tar.gz: 0b9a66a185ab03f7f345ff966b16c6b65558e6487356c4b4a7c580decf1c579f7a1e3d8ac9ca2e05fe8859da40abc284c06ea5a43aff7f758b332d618514ef1a
data/README.md CHANGED
@@ -100,8 +100,9 @@ end
100
100
 
101
101
  **Step 4**
102
102
 
103
- If you ran `bin/rails g tramway:install`, the Tailwind safelist was already appended to `config/tailwind.config.js`.
104
- Otherwise, copy this [file](https://github.com/Purple-Magic/tramway/blob/main/config/tailwind.config.js) to
103
+ If you ran `bin/rails g tramway:install`, the install generator already copied the Tailwind safelist to
104
+ `config/tailwind.config.js`.
105
+ Otherwise, copy this file from the gem:
105
106
  `config/tailwind.config.js`.
106
107
 
107
108
 
@@ -870,9 +871,10 @@ end
870
871
 
871
872
  ### Tramway Flash
872
873
 
873
- `tramway_flash` renders the Tailwind-styled flash component that Tramway uses in its layouts. Pass the flash text and type, and
874
- the helper will resolve the proper Tailwind color (for example `:success` -> green, `:warning` -> orange). You can also provide
875
- custom HTML options directly (e.g., `class:`, `data:`) and they will be merged into the flash container.
874
+ `tramway_flash` renders the dark shadcn-style flash component that Tramway uses in its layouts. Pass the flash text and type,
875
+ and the helper will resolve the proper dark semantic accent (for example `:success` -> green, `:warning` -> orange). Tramway
876
+ does not render a separate light flash theme. You can also provide custom HTML options directly (e.g., `class:`, `data:`) and
877
+ they will be merged into the flash container.
876
878
 
877
879
  ```haml
878
880
  -# Haml example
@@ -887,7 +889,7 @@ custom HTML options directly (e.g., `class:`, `data:`) and they will be merged i
887
889
  ```
888
890
 
889
891
  Use the `type` argument is compatible to [Lantern Color Palette](https://github.com/TrinityMonsters/tramway/blob/main/README.md#lantern-color-palette) or provide a `color:` keyword to set
890
- the Tailwind color family explicitly.
892
+ the semantic accent explicitly.
891
893
 
892
894
  ### Tramway Chat
893
895
 
@@ -1122,6 +1124,12 @@ Example 3: rendering button
1122
1124
 
1123
1125
  The `type` option maps semantic intent to [Lantern Color Palette](https://github.com/TrinityMonsters/tramway/blob/main/README.md#lantern-color-palette).
1124
1126
 
1127
+ Use `size:` to select one of the built-in button sizes: `:small`, `:medium`, or `:large`. The default is `:medium`.
1128
+
1129
+ ```erb
1130
+ <%= tramway_button path: '/projects', text: 'Projects', size: :small %>
1131
+ ```
1132
+
1125
1133
  * `tramway_badge` renders a Tailwind-styled badge with the provided `text`. Pass a semantic `type` (for example, `:success` or
1126
1134
  `:danger`) to use the built-in color mappings, or supply a custom Tailwind color family with `color:`. When you opt into a
1127
1135
  custom color, ensure the corresponding background utilities are available in your Tailwind safelist.
@@ -1152,7 +1160,9 @@ Tramway uses [Tailwind](https://tailwindcss.com/) by default. All UI helpers are
1152
1160
 
1153
1161
  #### tramway_form_for
1154
1162
 
1155
- Tramway provides `tramway_form_for` helper that renders Tailwind-styled forms by default.
1163
+ Tramway provides `tramway_form_for` helper that renders Tailwind-styled forms by default. Form inputs use hardcoded
1164
+ dark shadcn-style classes; Tramway does not render a separate light form theme.
1165
+ Checkboxes render dark while unchecked and use the light primary checked state.
1156
1166
 
1157
1167
  ```erb
1158
1168
  <%= tramway_form_for @user do |f| %>
@@ -1170,8 +1180,8 @@ Tramway provides `tramway_form_for` helper that renders Tailwind-styled forms by
1170
1180
 
1171
1181
  will render [this](https://play.tailwindcss.com/xho3LfjKkK)
1172
1182
 
1173
- Use `size:` to control the form sizing (`:small`, `:medium`, or `:large`). The default is `:medium`, and all fields rendered
1174
- within the form will use the same size value.
1183
+ Use `size:` to control the input sizing (`:small`, `:medium`, or `:large`). The default is `:medium`, and supported inputs
1184
+ rendered within the form will use the same size value.
1175
1185
 
1176
1186
  ```erb
1177
1187
  <%= tramway_form_for @user, size: :large do |f| %>
@@ -1298,6 +1308,7 @@ With `remote: true`, Tramway submits the form on each input `change` via inline
1298
1308
  ### Tailwind-styled pagination for Kaminari
1299
1309
 
1300
1310
  Tramway uses [Tailwind](https://tailwindcss.com/) by default. It has tailwind-styled pagination for [kaminari](https://github.com/kaminari/kaminari).
1311
+ Pagination components use hardcoded dark shadcn-style classes and do not render a separate light theme.
1301
1312
 
1302
1313
  #### How to use
1303
1314
 
@@ -0,0 +1,36 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class UiCheckbox extends Controller {
4
+ static targets = ["input", "button", "indicator"]
5
+
6
+ connect() {
7
+ this.sync()
8
+ }
9
+
10
+ toggle(event) {
11
+ event.preventDefault()
12
+
13
+ if (this.inputTarget.disabled) return
14
+
15
+ this.inputTarget.click()
16
+ this.sync()
17
+ }
18
+
19
+ sync() {
20
+ const checked = this.inputTarget.checked
21
+ const state = checked ? "checked" : "unchecked"
22
+
23
+ this.buttonTarget.setAttribute("aria-checked", checked.toString())
24
+ this.buttonTarget.dataset.state = state
25
+ this.buttonTarget.classList.toggle("border-zinc-50", checked)
26
+ this.buttonTarget.classList.toggle("bg-zinc-50", checked)
27
+ this.buttonTarget.classList.toggle("text-zinc-950", checked)
28
+ this.buttonTarget.classList.toggle("border-zinc-800", !checked)
29
+ this.buttonTarget.classList.toggle("bg-zinc-950", !checked)
30
+ this.buttonTarget.classList.toggle("text-zinc-50", !checked)
31
+ this.indicatorTarget.classList.toggle("hidden", !checked)
32
+ this.buttonTarget.toggleAttribute("disabled", this.inputTarget.disabled)
33
+ }
34
+ }
35
+
36
+ export { UiCheckbox }
@@ -42,45 +42,42 @@ class TailwindComponent < Tramway::BaseComponent
42
42
  private
43
43
 
44
44
  def text_input_base_classes
45
- theme_classes(
46
- classic: 'w-full rounded-xl border border-gray-700 bg-gray-900 text-gray-100 shadow-inner ' \
47
- 'focus:outline-none focus:ring-2 focus:ring-gray-600 placeholder-gray-500'
48
- )
45
+ 'w-full rounded-md border border-zinc-800 bg-zinc-950 text-zinc-50 shadow-sm transition-colors ' \
46
+ 'placeholder:text-zinc-500 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-300 ' \
47
+ 'focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 disabled:cursor-not-allowed ' \
48
+ 'disabled:opacity-50'
49
49
  end
50
50
 
51
51
  def select_base_classes
52
- theme_classes(
53
- classic: 'w-full rounded-xl border border-gray-700 bg-gray-900 text-gray-100 shadow-inner ' \
54
- 'focus:outline-none focus:ring-2 focus:ring-gray-600 disabled:cursor-not-allowed ' \
55
- 'disabled:bg-gray-800 disabled:text-gray-500'
56
- )
52
+ 'w-full rounded-md border border-zinc-800 bg-zinc-950 text-zinc-50 shadow-sm transition-colors ' \
53
+ 'appearance-none focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-300 ' \
54
+ 'focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 disabled:cursor-not-allowed ' \
55
+ 'disabled:opacity-50'
57
56
  end
58
57
 
59
58
  def file_button_base_classes
60
- theme_classes(
61
- classic: 'inline-block text-white font-semibold rounded-xl cursor-pointer mt-4 bg-blue-600 ' \
62
- 'hover:bg-blue-800 shadow-md'
63
- )
59
+ 'inline-flex items-center justify-center rounded-md border border-zinc-800 bg-zinc-950 text-zinc-50 ' \
60
+ 'font-medium shadow-sm transition-colors hover:bg-zinc-900 focus-visible:outline-none ' \
61
+ 'focus-visible:ring-2 focus-visible:ring-zinc-300 focus-visible:ring-offset-2 ' \
62
+ 'focus-visible:ring-offset-zinc-950 disabled:pointer-events-none disabled:opacity-50 cursor-pointer mt-4'
64
63
  end
65
64
 
66
65
  def submit_button_base_classes
67
- theme_classes(
68
- classic: 'font-semibold rounded-xl focus:outline-none focus:ring-2 focus:ring-red-700 cursor-pointer ' \
69
- 'bg-green-900 hover:bg-green-800 shadow-md'
70
- )
66
+ 'font-medium rounded-md border border-zinc-800 bg-zinc-950 text-zinc-50 shadow-sm transition-colors ' \
67
+ 'hover:bg-zinc-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-300 ' \
68
+ 'focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 cursor-pointer'
71
69
  end
72
70
 
73
71
  def checkbox_base_classes
74
- theme_classes(
75
- classic: 'rounded-full border border-gray-700 bg-gray-900 text-gray-100 shadow-inner focus:outline-none ' \
76
- 'focus:ring-2 focus:ring-gray-600'
77
- )
72
+ 'shrink-0 rounded-sm border border-zinc-800 bg-zinc-950 text-zinc-50 shadow-sm ' \
73
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-300 ' \
74
+ 'focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 disabled:cursor-not-allowed ' \
75
+ 'disabled:opacity-50'
78
76
  end
79
77
 
80
78
  def form_label_classes
81
- theme_classes(
82
- classic: 'block text-sm font-semibold mb-2 text-gray-200'
83
- )
79
+ 'block text-sm font-medium leading-none mb-2 text-zinc-200 peer-disabled:cursor-not-allowed ' \
80
+ 'peer-disabled:opacity-70'
84
81
  end
85
82
 
86
83
  def default_container_classes
@@ -4,6 +4,12 @@ module Tramway
4
4
  # Default Tramway button
5
5
  #
6
6
  class ButtonComponent < BaseComponent
7
+ DEFAULT_BUTTON_CLASSES = %w[
8
+ inline-flex items-center justify-center rounded-md font-medium ring-offset-background transition-colors
9
+ focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2
10
+ disabled:pointer-events-none disabled:opacity-50
11
+ ].freeze
12
+
7
13
  option :text, optional: true, default: -> {}
8
14
  option :path, optional: true, default: -> { '#' }
9
15
  option :color, optional: true
@@ -29,42 +35,44 @@ module Tramway
29
35
  end
30
36
 
31
37
  def size_classes
32
- unless size.in?(%i[small medium large])
38
+ unless normalized_size.in?(%i[small medium large])
33
39
  raise ArgumentError, "Invalid size: #{size}. Valid sizes are :small, :medium, :large."
34
40
  end
35
41
 
36
42
  {
37
43
  small: 'text-sm py-1 px-2 rounded',
38
- medium: 'py-2 px-4 h-10',
44
+ medium: 'text-sm py-2 px-4 h-10',
39
45
  large: 'text-xl px-5 py-3 h-12'
40
- }[size]
46
+ }[normalized_size]
47
+ end
48
+
49
+ def default_button_classes
50
+ DEFAULT_BUTTON_CLASSES
41
51
  end
42
52
 
43
53
  def classes
44
- (default_classes +
54
+ (default_button_classes +
55
+ size_classes.split +
45
56
  color_classes +
46
- (@tag == :a ? %w[px-1 h-fit w-fit] : [cursor_class])).compact.join(' ')
57
+ (@tag == :a ? %w[px-1 h-fit w-fit] : [cursor_class]) +
58
+ options[:class].to_s.split).compact.join(' ')
47
59
  end
48
60
 
49
- def default_classes
50
- base_classes = theme_classes(
51
- classic: %w[btn btn-primary flex flex-row font-semibold rounded-xl whitespace-nowrap items-center gap-1
52
- shadow-md]
53
- )
54
-
55
- base_classes + [size_classes.to_s, options[:class].to_s]
61
+ def color_classes
62
+ theme_classes classic: color_classes_collection
56
63
  end
57
64
 
58
- def color_classes
59
- if disabled?
60
- %w[bg-gray-800 text-gray-500 shadow-inner]
61
- else
62
- [
63
- "bg-#{resolved_color}-700", "hover:bg-#{resolved_color}-800", 'text-white'
64
- ]
65
- end => classes_collection
65
+ def color_classes_collection
66
+ return %w[bg-gray-800 text-gray-500 shadow-inner] if disabled?
66
67
 
67
- theme_classes classic: classes_collection
68
+ case normalized_type
69
+ when :default, :life, :secondary
70
+ ['hover:bg-zinc-250', 'bg-zinc-50', 'text-zinc-950']
71
+ when :inverse
72
+ ['hover:bg-zinc-800', 'bg-zinc-950', 'text-zinc-50', 'border', 'border-zinc-800']
73
+ else
74
+ ["hover:bg-#{resolved_color}-900 bg-#{resolved_color}-900/30 text-#{resolved_color}-400"]
75
+ end
68
76
  end
69
77
 
70
78
  def disabled?
@@ -98,6 +106,10 @@ module Tramway
98
106
  end
99
107
  end
100
108
 
109
+ def normalized_size
110
+ size || :medium
111
+ end
112
+
101
113
  def tag_button?
102
114
  options[:type] == :submit
103
115
  end
@@ -1,19 +1,19 @@
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', data: { scroll_to_bottom_on_update: scroll_to_bottom_on_update } }
4
+ #messages.flex.flex-col.flex-1.min-h-0.overflow-y-auto.overflow-x-hidden.rounded-xl.rounded-b-none.border.border-zinc-800.p-2.text-zinc-50.space-y-2.md:p-6.md:space-y-4{ data: { scroll_to_bottom_on_update: scroll_to_bottom_on_update }, class: 'bg-zinc-950/80' }
5
5
  - messages.each do |message|
6
6
  = component "tramway/chats/message", **message
7
7
  - if disabled?
8
- = inline_svg 'icons/dots.svg', class: 'w-8 h-8 text-gray-500 mx-auto my-4'
8
+ = inline_svg 'icons/dots.svg', class: 'mx-auto my-4 h-8 w-8 text-zinc-500'
9
9
 
10
10
  - if message_form.present?
11
- .shrink-0.border-gray-200.md:pt-2.border-gray-700
12
- = form_for message_form, url: send_message_path, as: :message, method: :post, html: { class: 'flex items-center md:gap-1' } do |f|
11
+ .shrink-0.border-t.border-zinc-800.pt-2
12
+ = form_for message_form, url: send_message_path, as: :message, method: :post, html: { class: 'flex items-center gap-2 md:gap-1' } do |f|
13
13
  - waiting_placeholder = t('tramway.chat.placeholders.waiting')
14
14
  - typing_placeholder = t('tramway.chat.placeholders.type')
15
15
  = f.text_field :text,
16
- class: 'flex-1 md:rounded-full rounded-bl-2xl md:border border-gray-300 px-4 py-2 text-sm text-gray-900 shadow-sm placeholder:text-gray-400 focus:border-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-200 disabled:cursor-not-allowed border-gray-600 bg-gray-800 text-white focus:border-blue-400 focus:ring-blue-500/30',
16
+ class: 'flex-1 appearance-none rounded-md border border-zinc-800 bg-zinc-900 px-4 py-2 text-sm text-zinc-50 shadow-sm outline-none placeholder:text-zinc-500 focus:outline-none focus:ring-0 focus-visible:outline-none focus-visible:ring-0 focus-visible:ring-offset-0 disabled:cursor-not-allowed',
17
17
  placeholder: send_messages_enabled ? typing_placeholder : waiting_placeholder,
18
18
  disabled: !send_messages_enabled
19
19
 
@@ -23,7 +23,7 @@
23
23
  = f.hidden_field key, value: value
24
24
 
25
25
  = f.submit '🡩',
26
- class: 'md:rounded-full bg-blue-600 px-4 py-2 text-sm font-semibold text-white shadow-sm hover:bg-blue-500 focus:outline-none focus:ring-2 focus:ring-blue-200 bg-blue-500 hover:bg-blue-400 cursor-pointer'
26
+ class: 'inline-flex items-center justify-center rounded-md bg-zinc-50 px-4 py-2 text-sm font-medium text-zinc-950 shadow-sm transition-colors hover:bg-zinc-200 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-400 focus-visible:ring-offset-2 focus-visible:ring-offset-zinc-950 disabled:pointer-events-none disabled:opacity-50'
27
27
 
28
28
  :javascript
29
29
  (() => {
@@ -16,11 +16,11 @@
16
16
 
17
17
  - if pending?
18
18
  .pb-1
19
- -# = inline_svg 'icons/spinner.svg', class: 'w-4 h-4 text-white animate-spin'
19
+ -# = inline_svg 'icons/spinner.svg', class: 'h-4 w-4 animate-spin text-zinc-50'
20
20
 
21
21
  - if failed?
22
22
  .pb-1
23
- -# = inline_svg 'icons/cross.svg', class: 'w-6 h-6 text-red-200'
23
+ -# = inline_svg 'icons/cross.svg', class: 'h-6 w-6 text-red-400'
24
24
 
25
25
  - if data_view == :table
26
26
  = component 'tramway/chats/messages/table', data:
@@ -20,9 +20,9 @@ module Tramway
20
20
 
21
21
  def text_color
22
22
  if pending?
23
- 'text-gray-400 dark:text-gray-600'
23
+ 'text-zinc-500'
24
24
  else
25
- 'text-black dark:text-white'
25
+ 'text-zinc-50'
26
26
  end
27
27
  end
28
28
 
@@ -1,9 +1,9 @@
1
1
  .flex.flex-col.gap-1{ class: position_classes }
2
2
  - if text.present?
3
- .max-w-lg.rounded-2xl.px-4.py-3.text-sm.shadow-sm.ring-1.text-white.ring-gray-700{ class: color_classes }
4
- = component 'tramway/native_text', text:, klass: 'text-white'
3
+ .max-w-lg.rounded-2xl.px-4.py-3.text-sm.shadow-sm{ class: color_classes }
4
+ = component 'tramway/native_text', text:, klass: 'text-zinc-50'
5
5
 
6
6
  - if sent_at.present?
7
- .mt-2.text-right.text-xs.text-gray-400
7
+ .mt-2.text-right.text-xs.text-zinc-400
8
8
  = sent_at
9
9
  = content
@@ -10,21 +10,16 @@ module Tramway
10
10
  option :sent_at
11
11
 
12
12
  def position_classes
13
- case position.to_sym
14
- when :left
15
- %w[items-start]
16
- when :right
17
- %w[items-end]
18
- end.join(' ')
13
+ position.to_sym == :left ? 'items-start' : 'items-end'
19
14
  end
20
15
 
21
16
  def color_classes
22
17
  case position.to_sym
23
18
  when :left
24
- %w[bg-gray-800 rounded-tl-md]
19
+ 'rounded-tl-md bg-zinc-900 text-zinc-50'
25
20
  when :right
26
- %w[bg-blue-600 rounded-tr-md]
27
- end.join(' ')
21
+ 'rounded-tr-md bg-zinc-800 text-zinc-50'
22
+ end
28
23
  end
29
24
  end
30
25
  end
@@ -1,4 +1,4 @@
1
- .mt-3.overflow-hidden.rounded-xl.border.border-gray-200.bg-white.shadow-sm.dark:border-gray-700.dark:bg-gray-900
1
+ .mt-3.overflow-hidden.rounded-xl.border.border-zinc-800.bg-zinc-950.shadow-sm
2
2
  = tramway_table do
3
3
  - data.each_with_index do |row, index|
4
4
  - if index.zero?
@@ -4,8 +4,9 @@ module Tramway
4
4
  # Color logic implementation
5
5
  module ColorsMethods
6
6
  TYPE_COLOR_MAP = {
7
- default: :gray,
8
- life: :gray,
7
+ default: :zinc,
8
+ inverse: :zinc,
9
+ life: :zinc,
9
10
  primary: :blue,
10
11
  hope: :blue,
11
12
  secondary: :zinc,
@@ -17,7 +18,6 @@ module Tramway
17
18
  rage: :red,
18
19
  love: :violet,
19
20
  compassion: :indigo,
20
- compassio: :indigo,
21
21
  fear: :yellow,
22
22
  submit: :green
23
23
  }.freeze
@@ -10,7 +10,7 @@ module Tramway
10
10
  options_classes = options[:class] || ''
11
11
 
12
12
  theme_classes(
13
- classic: "bg-gray-900 text-gray-100 shadow-inner#{options_classes}"
13
+ classic: "bg-zinc-950 text-zinc-50 shadow-inner#{options_classes}"
14
14
  )
15
15
  end
16
16
  end
@@ -11,8 +11,8 @@ module Tramway
11
11
  options_classes = options[:class] || ''
12
12
 
13
13
  theme_classes(
14
- classic: 'container p-4 flex align-center justify-center w-full mx-auto bg-gray-100 text-gray-700 ' \
15
- 'shadow-inner rounded-xl bg-gray-900 text-gray-100' + options_classes
14
+ classic: 'container p-4 flex align-center justify-center w-full mx-auto ' \
15
+ 'shadow-inner rounded-xl bg-zinc-950 text-zinc-50' + options_classes
16
16
  )
17
17
  end
18
18
  end
@@ -15,7 +15,6 @@
15
15
 
16
16
  .flash {
17
17
  animation: fadeout 2.7s ease-out forwards;
18
- pointer-events: none;
19
18
  }
20
19
 
21
20
  %div{ class: container_classes, **options }
@@ -11,22 +11,37 @@ module Tramway
11
11
  include Tramway::ColorsMethods
12
12
 
13
13
  def container_classes
14
- theme_classes(
15
- classic: 'fixed top-4 right-4 z-50 space-y-2 pointer-events-none'
16
- )
14
+ 'fixed top-4 right-4 z-50 flex w-fit max-w-sm flex-col gap-2 pointer-events-none'
17
15
  end
18
16
 
19
17
  def flash_classes
20
- theme_classes(
21
- classic: "flash opacity-100 px-4 py-2 rounded-xl shadow-md bg-#{resolved_color}-100 " \
22
- "text-#{resolved_color}-800"
23
- )
18
+ (base_flash_classes + semantic_flash_classes).join(' ')
24
19
  end
25
20
 
26
21
  def title_classes
27
- theme_classes(
28
- classic: 'text-xl font-semibold'
29
- )
22
+ 'text-sm font-medium leading-6'
23
+ end
24
+
25
+ private
26
+
27
+ def base_flash_classes
28
+ %w[
29
+ flash pointer-events-auto opacity-100 rounded-md border bg-zinc-950 px-4 py-3 text-sm text-zinc-50
30
+ shadow-lg
31
+ ]
32
+ end
33
+
34
+ def semantic_flash_classes
35
+ {
36
+ green: %w[border-green-800 text-green-400],
37
+ blue: %w[border-blue-800 text-blue-400],
38
+ orange: %w[border-orange-800 text-orange-400],
39
+ red: %w[border-red-800 text-red-400],
40
+ violet: %w[border-violet-800 text-violet-400],
41
+ indigo: %w[border-indigo-800 text-indigo-400],
42
+ yellow: %w[border-yellow-800 text-yellow-400],
43
+ zinc: %w[border-zinc-800 text-zinc-50]
44
+ }.fetch(resolved_color.to_sym, %w[border-zinc-800 text-zinc-50])
30
45
  end
31
46
  end
32
47
  end
@@ -103,7 +103,7 @@ module Tramway
103
103
  Tramway::ButtonComponent.new(
104
104
  text: action,
105
105
  size: form_size,
106
- type: :will,
106
+ type: :inverse,
107
107
  options: sanitized_options.merge(name: :commit, type: :submit)
108
108
  ),
109
109
  &
@@ -1,7 +1,29 @@
1
- .flex.items-center.gap-2.cursor-pointer{ class: default_container_classes }
2
- - classes = "#{size_class(:checkbox_input)} #{checkbox_base_classes}"
3
- = @input.call @attribute, **@options.merge(class: classes)
1
+ .flex.items-center.space-x-2{ class: default_container_classes, data: { controller: 'ui--checkbox' } }
2
+ - checkbox_checked = checked?
3
+ = @input.call @attribute, **hidden_checkbox_options
4
+ %button{ type: 'button',
5
+ role: 'checkbox',
6
+ 'aria-checked' => checkbox_checked.to_s,
7
+ 'data-action' => 'click->ui--checkbox#toggle',
8
+ 'data-state' => checkbox_checked ? 'checked' : 'unchecked',
9
+ 'data-ui--checkbox-target' => 'button',
10
+ value: 'on',
11
+ class: checkbox_button_classes,
12
+ for: @for,
13
+ id: @for }
14
+ %span{ class: checkbox_indicator_classes, style: 'pointer-events: none', data: { 'ui--checkbox-target' => 'indicator' } }
15
+ %svg{ xmlns: 'http://www.w3.org/2000/svg',
16
+ width: '24',
17
+ height: '24',
18
+ viewBox: '0 0 24 24',
19
+ fill: 'none',
20
+ stroke: 'currentColor',
21
+ 'stroke-width' => '2',
22
+ 'stroke-linecap' => 'round',
23
+ 'stroke-linejoin' => 'round',
24
+ class: 'h-4 w-4' }
25
+ %polyline{ points: '20 6 9 17 4 12' }
4
26
  - if @label
5
27
  %div
6
- = component('tramway/form/label', for: @for, options: { class: label_classes }) do
28
+ = component('tramway/form/label', for: @for, options: { class: label_classes, data: { action: 'click->ui--checkbox#toggle' } }) do
7
29
  = @label
@@ -4,8 +4,39 @@ module Tramway
4
4
  module Form
5
5
  # Tailwind-styled checkbox field
6
6
  class CheckboxComponent < TailwindComponent
7
+ def checkbox_button_classes
8
+ 'peer h-4 w-4 shrink-0 rounded-sm border border-zinc-800 bg-zinc-950 text-zinc-50 ' \
9
+ 'ring-offset-zinc-950 ' \
10
+ 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-zinc-300 ' \
11
+ 'focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ' \
12
+ 'data-[state=checked]:border-zinc-50 data-[state=checked]:bg-zinc-50 ' \
13
+ 'data-[state=checked]:text-zinc-950'
14
+ end
15
+
16
+ def checkbox_indicator_classes
17
+ 'flex items-center justify-center text-current hidden'
18
+ end
19
+
20
+ def checked?
21
+ !!ActiveModel::Type::Boolean.new.cast(options.fetch(:checked, value))
22
+ end
23
+
24
+ def hidden_checkbox_options
25
+ options.merge(
26
+ id: hidden_checkbox_id,
27
+ class: 'hidden',
28
+ data: options.fetch(:data, {}).merge('ui--checkbox-target' => 'input'),
29
+ tabindex: -1,
30
+ aria: { hidden: true }
31
+ )
32
+ end
33
+
34
+ def hidden_checkbox_id
35
+ "#{@for}_input"
36
+ end
37
+
7
38
  def label_classes
8
- default_classes = 'cursor-pointer mb-0'
39
+ default_classes = 'cursor-pointer mb-0 leading-6'
9
40
 
10
41
  case size
11
42
  when :small
@@ -1,2 +1,2 @@
1
- %label{ for: @for, class: "#{form_label_classes} #{options[:class]}" }
1
+ %label{ **options.except(:class), for: @for, class: "#{form_label_classes} #{options[:class]}" }
2
2
  = content
@@ -8,9 +8,8 @@ module Tramway
8
8
  option :options, optional: true, default: -> { {} }
9
9
 
10
10
  def form_label_classes
11
- theme_classes(
12
- classic: 'block font-semibold text-white'
13
- )
11
+ 'block text-sm font-medium leading-none mb-2 text-zinc-200 peer-disabled:cursor-not-allowed ' \
12
+ 'peer-disabled:opacity-70'
14
13
  end
15
14
  end
16
15
  end
@@ -14,11 +14,8 @@ module Tramway
14
14
  }.freeze
15
15
 
16
16
  def dropdown_classes
17
- theme_classes(
18
- classic: 'absolute border-b border-l border-r border-gray-700 w-full z-40 lef-0 rounded-b-xl' \
19
- 'max-h-select overflow-y-auto bg-gray-900 shadow-md ring-1 ring-gray-700 text-white ' \
20
- "#{SIZE_CLASSES[size]}"
21
- )
17
+ 'absolute border border-zinc-800 w-full z-40 lef-0 rounded-md max-h-select overflow-y-auto ' \
18
+ "bg-zinc-950 text-zinc-50 shadow-md ring-1 ring-zinc-800 #{SIZE_CLASSES[size]}"
22
19
  end
23
20
  end
24
21
  end
@@ -14,9 +14,7 @@ module Tramway
14
14
  }.freeze
15
15
 
16
16
  def item_classes
17
- theme_classes(
18
- classic: "cursor-pointer hover:bg-gray-800 shadow-inner option #{SIZE_CLASSES[size]}"
19
- )
17
+ "cursor-pointer rounded-sm text-zinc-50 hover:bg-zinc-900 option #{SIZE_CLASSES[size]}"
20
18
  end
21
19
  end
22
20
  end
@@ -11,10 +11,7 @@ module Tramway
11
11
  option :size_class
12
12
 
13
13
  def base_classes
14
- theme_classes(
15
- classic: 'bg-transparent appearance-none outline-none h-full w-full hidden text-gray-100 ' \
16
- 'placeholder-gray-500'
17
- )
14
+ 'bg-transparent appearance-none outline-none h-full w-full hidden text-zinc-50 placeholder:text-zinc-500'
18
15
  end
19
16
  end
20
17
  end