solidus_admin 0.0.2 → 0.2.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.
Files changed (251) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc.json +7 -0
  3. data/README.md +2 -2
  4. data/Rakefile +26 -0
  5. data/app/assets/builds/.keep +0 -0
  6. data/app/assets/builds/solidus_admin/tailwind.css +2799 -0
  7. data/app/assets/config/solidus_admin_manifest.js +1 -0
  8. data/app/assets/stylesheets/solidus_admin/application.tailwind.css +4 -0
  9. data/app/assets/stylesheets/solidus_admin/dark.css +12 -0
  10. data/app/assets/stylesheets/solidus_admin/dimmed.css +11 -0
  11. data/app/components/solidus_admin/adjustment_reasons/index/component.rb +43 -0
  12. data/app/components/solidus_admin/base_component.rb +29 -1
  13. data/app/components/solidus_admin/layout/feedback/component.html.erb +15 -0
  14. data/app/components/solidus_admin/layout/feedback/component.rb +4 -0
  15. data/app/components/solidus_admin/layout/feedback/component.yml +3 -0
  16. data/app/components/solidus_admin/layout/navigation/account/component.html.erb +74 -0
  17. data/app/components/solidus_admin/layout/navigation/account/component.js +16 -0
  18. data/app/components/solidus_admin/layout/navigation/account/component.rb +36 -0
  19. data/app/components/solidus_admin/{sidebar → layout/navigation}/component.html.erb +9 -9
  20. data/app/components/solidus_admin/layout/navigation/component.rb +26 -0
  21. data/app/components/solidus_admin/{sidebar → layout/navigation}/item/component.html.erb +5 -5
  22. data/app/components/solidus_admin/{sidebar → layout/navigation}/item/component.rb +2 -2
  23. data/app/components/solidus_admin/layout/page_helpers.rb +55 -0
  24. data/app/components/solidus_admin/{skip_link → layout/skip_link}/component.rb +2 -4
  25. data/app/components/solidus_admin/option_types/index/component.rb +71 -0
  26. data/app/components/solidus_admin/orders/cart/component.html.erb +77 -0
  27. data/app/components/solidus_admin/orders/cart/component.js +37 -0
  28. data/app/components/solidus_admin/orders/cart/component.rb +7 -0
  29. data/app/components/solidus_admin/orders/cart/component.yml +3 -0
  30. data/app/components/solidus_admin/orders/cart/result/component.html.erb +26 -0
  31. data/app/components/solidus_admin/orders/cart/result/component.rb +11 -0
  32. data/app/components/solidus_admin/orders/index/component.rb +92 -23
  33. data/app/components/solidus_admin/orders/index/component.yml +10 -4
  34. data/app/components/solidus_admin/orders/show/address/component.html.erb +67 -0
  35. data/app/components/solidus_admin/orders/show/address/component.js +9 -0
  36. data/app/components/solidus_admin/orders/show/address/component.rb +53 -0
  37. data/app/components/solidus_admin/orders/show/address/component.yml +14 -0
  38. data/app/components/solidus_admin/orders/show/component.html.erb +76 -0
  39. data/app/components/solidus_admin/orders/show/component.js +7 -0
  40. data/app/components/solidus_admin/orders/show/component.rb +40 -0
  41. data/app/components/solidus_admin/orders/show/component.yml +21 -0
  42. data/app/components/solidus_admin/orders/show/customer_search/component.html.erb +14 -0
  43. data/app/components/solidus_admin/orders/show/customer_search/component.js +14 -0
  44. data/app/components/solidus_admin/orders/show/customer_search/component.rb +7 -0
  45. data/app/components/solidus_admin/orders/show/customer_search/component.yml +2 -0
  46. data/app/components/solidus_admin/orders/show/customer_search/result/component.html.erb +17 -0
  47. data/app/components/solidus_admin/orders/show/customer_search/result/component.rb +11 -0
  48. data/app/components/solidus_admin/orders/show/email/component.html.erb +18 -0
  49. data/app/components/solidus_admin/orders/show/email/component.rb +15 -0
  50. data/app/components/solidus_admin/orders/show/email/component.yml +8 -0
  51. data/app/components/solidus_admin/orders/show/summary/component.html.erb +14 -0
  52. data/app/components/solidus_admin/orders/show/summary/component.rb +7 -0
  53. data/app/components/solidus_admin/orders/show/summary/component.yml +8 -0
  54. data/app/components/solidus_admin/payment_methods/index/component.rb +103 -0
  55. data/app/components/solidus_admin/payment_methods/index/component.yml +10 -0
  56. data/app/components/solidus_admin/products/index/component.rb +48 -41
  57. data/app/components/solidus_admin/products/index/component.yml +8 -7
  58. data/app/components/solidus_admin/products/show/component.html.erb +32 -38
  59. data/app/components/solidus_admin/products/show/component.rb +2 -0
  60. data/app/components/solidus_admin/products/show/component.yml +5 -5
  61. data/app/components/solidus_admin/products/status/component.rb +20 -18
  62. data/app/components/solidus_admin/products/status/component.yml +1 -0
  63. data/app/components/solidus_admin/products/stock/component.rb +38 -0
  64. data/app/components/solidus_admin/products/stock/component.yml +5 -0
  65. data/app/components/solidus_admin/promotion_categories/index/component.rb +56 -0
  66. data/app/components/solidus_admin/promotions/index/component.rb +104 -0
  67. data/app/components/solidus_admin/promotions/index/component.yml +10 -0
  68. data/app/components/solidus_admin/properties/index/component.rb +64 -0
  69. data/app/components/solidus_admin/refund_reasons/index/component.rb +53 -0
  70. data/app/components/solidus_admin/refunds_and_returns/component.rb +40 -0
  71. data/app/components/solidus_admin/refunds_and_returns/component.yml +3 -0
  72. data/app/components/solidus_admin/reimbursement_types/index/component.rb +27 -0
  73. data/app/components/solidus_admin/return_reasons/index/component.rb +42 -0
  74. data/app/components/solidus_admin/shipping/component.rb +30 -0
  75. data/app/components/solidus_admin/shipping/component.yml +3 -0
  76. data/app/components/solidus_admin/shipping_categories/index/component.rb +46 -0
  77. data/app/components/solidus_admin/shipping_methods/index/component.rb +61 -0
  78. data/app/components/solidus_admin/stock_items/edit/component.html.erb +89 -0
  79. data/app/components/solidus_admin/stock_items/edit/component.js +17 -0
  80. data/app/components/solidus_admin/stock_items/edit/component.rb +23 -0
  81. data/app/components/solidus_admin/stock_items/edit/component.yml +10 -0
  82. data/app/components/solidus_admin/stock_items/index/component.rb +174 -0
  83. data/app/components/solidus_admin/stock_items/index/component.yml +10 -0
  84. data/app/components/solidus_admin/stock_locations/index/component.rb +89 -0
  85. data/app/components/solidus_admin/stock_locations/index/component.yml +3 -0
  86. data/app/components/solidus_admin/store_credit_reasons/index/component.rb +52 -0
  87. data/app/components/solidus_admin/stores/index/component.rb +58 -0
  88. data/app/components/solidus_admin/tax_categories/index/component.rb +58 -0
  89. data/app/components/solidus_admin/tax_rates/index/component.rb +88 -0
  90. data/app/components/solidus_admin/taxes/component.rb +25 -0
  91. data/app/components/solidus_admin/taxes/component.yml +3 -0
  92. data/app/components/solidus_admin/taxonomies/index/component.rb +53 -0
  93. data/app/components/solidus_admin/ui/badge/component.rb +18 -8
  94. data/app/components/solidus_admin/ui/badge/component.yml +3 -0
  95. data/app/components/solidus_admin/ui/button/component.rb +32 -32
  96. data/app/components/solidus_admin/ui/details_list/component.html.erb +10 -0
  97. data/app/components/solidus_admin/ui/details_list/component.rb +7 -0
  98. data/app/components/solidus_admin/ui/dropdown/component.html.erb +50 -0
  99. data/app/components/solidus_admin/ui/dropdown/component.js +16 -0
  100. data/app/components/solidus_admin/ui/dropdown/component.rb +28 -0
  101. data/app/components/solidus_admin/ui/dropdown/component.yml +2 -0
  102. data/app/components/solidus_admin/ui/forms/address/component.html.erb +36 -0
  103. data/app/components/solidus_admin/ui/forms/address/component.js +34 -0
  104. data/app/components/solidus_admin/ui/forms/address/component.rb +14 -0
  105. data/app/components/solidus_admin/ui/forms/field/component.html.erb +5 -4
  106. data/app/components/solidus_admin/ui/forms/field/component.rb +53 -15
  107. data/app/components/solidus_admin/ui/forms/input/component.rb +11 -5
  108. data/app/components/solidus_admin/ui/forms/search/component.html.erb +52 -0
  109. data/app/components/solidus_admin/ui/forms/search/component.js +116 -0
  110. data/app/components/solidus_admin/ui/forms/search/component.rb +8 -0
  111. data/app/components/solidus_admin/ui/forms/search/component.yml +4 -0
  112. data/app/components/solidus_admin/ui/forms/search/result/component.rb +12 -0
  113. data/app/components/solidus_admin/ui/forms/search_field/component.html.erb +20 -0
  114. data/app/{javascript/solidus_admin/controllers/hello_controller.js → components/solidus_admin/ui/forms/search_field/component.js} +4 -2
  115. data/app/components/solidus_admin/ui/forms/search_field/component.rb +10 -0
  116. data/app/components/solidus_admin/ui/forms/search_field/component.yml +2 -0
  117. data/app/components/solidus_admin/ui/forms/switch/component.rb +27 -31
  118. data/app/components/solidus_admin/ui/forms/switch_field/component.html.erb +20 -0
  119. data/app/components/solidus_admin/ui/forms/switch_field/component.rb +11 -0
  120. data/app/components/solidus_admin/ui/icon/component.rb +4 -0
  121. data/app/components/solidus_admin/ui/modal/component.html.erb +37 -0
  122. data/app/components/solidus_admin/ui/modal/component.rb +12 -0
  123. data/app/components/solidus_admin/ui/modal/component.yml +2 -0
  124. data/app/components/solidus_admin/ui/pages/index/component.html.erb +30 -0
  125. data/app/components/solidus_admin/ui/pages/index/component.rb +119 -0
  126. data/app/components/solidus_admin/ui/pages/index/component.yml +4 -0
  127. data/app/components/solidus_admin/ui/panel/component.html.erb +26 -12
  128. data/app/components/solidus_admin/ui/panel/component.rb +17 -0
  129. data/app/components/solidus_admin/ui/panel/component.yml +1 -3
  130. data/app/components/solidus_admin/ui/resource_item/component.html.erb +10 -0
  131. data/app/components/solidus_admin/ui/resource_item/component.rb +9 -0
  132. data/app/components/solidus_admin/ui/tab/component.rb +9 -8
  133. data/app/components/solidus_admin/ui/table/component.html.erb +147 -135
  134. data/app/components/solidus_admin/ui/table/component.js +56 -17
  135. data/app/components/solidus_admin/ui/table/component.rb +94 -70
  136. data/app/components/solidus_admin/ui/table/component.yml +0 -1
  137. data/app/components/solidus_admin/ui/table/ransack_filter/component.html.erb +72 -0
  138. data/app/components/solidus_admin/ui/table/ransack_filter/component.js +73 -0
  139. data/app/components/solidus_admin/ui/table/ransack_filter/component.rb +68 -0
  140. data/app/components/solidus_admin/ui/table/ransack_filter/component.yml +3 -0
  141. data/app/components/solidus_admin/ui/table/toolbar/component.rb +21 -0
  142. data/app/components/solidus_admin/ui/thumbnail/component.rb +46 -0
  143. data/app/components/solidus_admin/ui/toast/component.html.erb +9 -5
  144. data/app/components/solidus_admin/ui/toast/component.js +9 -6
  145. data/app/components/solidus_admin/ui/toast/component.rb +2 -2
  146. data/app/components/solidus_admin/ui/toggletip/component.html.erb +14 -10
  147. data/app/components/solidus_admin/ui/toggletip/component.js +22 -4
  148. data/app/components/solidus_admin/ui/toggletip/component.rb +8 -85
  149. data/app/components/solidus_admin/users/index/component.rb +96 -0
  150. data/app/components/solidus_admin/users/index/component.yml +15 -0
  151. data/app/components/solidus_admin/zones/index/component.rb +63 -0
  152. data/app/controllers/solidus_admin/addresses_controller.rb +92 -0
  153. data/app/controllers/solidus_admin/adjustment_reasons_controller.rb +40 -0
  154. data/app/controllers/solidus_admin/base_controller.rb +1 -0
  155. data/app/controllers/solidus_admin/controller_helpers/authorization.rb +5 -1
  156. data/app/controllers/solidus_admin/controller_helpers/locale.rb +2 -2
  157. data/app/controllers/solidus_admin/controller_helpers/search.rb +48 -0
  158. data/app/controllers/solidus_admin/controller_helpers/theme.rb +30 -0
  159. data/app/controllers/solidus_admin/countries_controller.rb +12 -0
  160. data/app/controllers/solidus_admin/customers_controller.rb +29 -0
  161. data/app/controllers/solidus_admin/line_items_controller.rb +45 -0
  162. data/app/controllers/solidus_admin/option_types_controller.rb +46 -0
  163. data/app/controllers/solidus_admin/orders_controller.rb +104 -7
  164. data/app/controllers/solidus_admin/payment_methods_controller.rb +52 -0
  165. data/app/controllers/solidus_admin/products_controller.rb +26 -17
  166. data/app/controllers/solidus_admin/promotion_categories_controller.rb +29 -0
  167. data/app/controllers/solidus_admin/promotions_controller.rb +46 -0
  168. data/app/controllers/solidus_admin/properties_controller.rb +33 -0
  169. data/app/controllers/solidus_admin/refund_reasons_controller.rb +40 -0
  170. data/app/controllers/solidus_admin/reimbursement_types_controller.rb +31 -0
  171. data/app/controllers/solidus_admin/return_reasons_controller.rb +40 -0
  172. data/app/controllers/solidus_admin/shipping_categories_controller.rb +40 -0
  173. data/app/controllers/solidus_admin/shipping_methods_controller.rb +40 -0
  174. data/app/controllers/solidus_admin/stock_items_controller.rb +67 -0
  175. data/app/controllers/solidus_admin/stock_locations_controller.rb +40 -0
  176. data/app/controllers/solidus_admin/store_credit_reasons_controller.rb +40 -0
  177. data/app/controllers/solidus_admin/stores_controller.rb +40 -0
  178. data/app/controllers/solidus_admin/tax_categories_controller.rb +40 -0
  179. data/app/controllers/solidus_admin/tax_rates_controller.rb +40 -0
  180. data/app/controllers/solidus_admin/taxonomies_controller.rb +46 -0
  181. data/app/controllers/solidus_admin/users_controller.rb +50 -0
  182. data/app/controllers/solidus_admin/zones_controller.rb +40 -0
  183. data/app/javascript/solidus_admin/controllers/components.js +3 -1
  184. data/app/javascript/solidus_admin/controllers/confirm_controller.js +21 -0
  185. data/app/javascript/solidus_admin/controllers/details_click_outside_controller.js +12 -0
  186. data/app/javascript/solidus_admin/controllers/readonly_when_submitting_controller.js +17 -0
  187. data/app/javascript/solidus_admin/controllers/sortable_controller.js +33 -0
  188. data/app/views/layouts/solidus_admin/application.html.erb +16 -10
  189. data/app/views/layouts/solidus_admin/preview.html.erb +2 -1
  190. data/app/views/solidus_admin/base/unauthorized.html.erb +4 -0
  191. data/config/importmap.rb +2 -0
  192. data/config/initializers/view_component.rb +20 -0
  193. data/config/locales/adjustment_reasons.en.yml +6 -0
  194. data/config/locales/customers.en.yml +7 -0
  195. data/config/locales/errors.en.yml +7 -0
  196. data/config/locales/line_items.en.yml +9 -0
  197. data/config/locales/{main_nav.en.yml → menu_item.en.yml} +8 -2
  198. data/config/locales/option_types.en.yml +6 -0
  199. data/config/locales/orders.en.yml +9 -0
  200. data/config/locales/payment_methods.en.yml +6 -0
  201. data/config/locales/promotion_categories.en.yml +6 -0
  202. data/config/locales/promotions.en.yml +6 -0
  203. data/config/locales/properties.en.yml +6 -0
  204. data/config/locales/refund_reasons_.en.yml +6 -0
  205. data/config/locales/reimbursement_types.en.yml +4 -0
  206. data/config/locales/return_reasons.en.yml +6 -0
  207. data/config/locales/shipping_categories.en.yml +6 -0
  208. data/config/locales/shipping_methods.en.yml +6 -0
  209. data/config/locales/stock_items.en.yml +4 -0
  210. data/config/locales/stock_locations.en.yml +6 -0
  211. data/config/locales/store_credit_reasons.en.yml +6 -0
  212. data/config/locales/stores.en.yml +6 -0
  213. data/config/locales/tax_categories.en.yml +6 -0
  214. data/config/locales/tax_rates.en.yml +6 -0
  215. data/config/locales/taxonomies.en.yml +6 -0
  216. data/config/locales/users.en.yml +6 -0
  217. data/config/locales/zones.en.yml +6 -0
  218. data/config/routes.rb +50 -3
  219. data/config/tailwind.config.js +119 -0
  220. data/docs/{customizing_main_navigation.md → customizing_menu_items.md} +2 -2
  221. data/docs/customizing_tailwindcss.md +57 -0
  222. data/docs/customizing_view_components.md +17 -38
  223. data/lib/generators/solidus_admin/install/install_generator.rb +13 -4
  224. data/lib/generators/solidus_admin/install/templates/config/initializers/{solidus_admin.rb → solidus_admin.rb.tt} +10 -14
  225. data/lib/solidus_admin/admin_resources.rb +23 -0
  226. data/lib/solidus_admin/configuration.rb +95 -67
  227. data/lib/solidus_admin/install_tailwindcss.rb +102 -0
  228. data/lib/solidus_admin/{main_nav_item.rb → menu_item.rb} +2 -2
  229. data/lib/solidus_admin/version.rb +1 -1
  230. data/lib/solidus_admin.rb +1 -2
  231. data/lib/tasks/tailwind.rake +10 -0
  232. data/solidus_admin.gemspec +3 -4
  233. metadata +193 -50
  234. data/app/assets/stylesheets/solidus_admin/application.tailwind.css.erb +0 -35
  235. data/app/components/solidus_admin/feedback/component.html.erb +0 -11
  236. data/app/components/solidus_admin/feedback/component.rb +0 -4
  237. data/app/components/solidus_admin/feedback/component.yml +0 -5
  238. data/app/components/solidus_admin/orders/index/component.html.erb +0 -31
  239. data/app/components/solidus_admin/products/index/component.html.erb +0 -30
  240. data/app/components/solidus_admin/sidebar/account_nav/component.html.erb +0 -67
  241. data/app/components/solidus_admin/sidebar/account_nav/component.rb +0 -15
  242. data/app/components/solidus_admin/sidebar/component.rb +0 -21
  243. data/app/components/solidus_admin/ui/panel/component.js +0 -14
  244. data/config/solidus_admin/tailwind.config.js.erb +0 -95
  245. data/docs/customizing_tailwind.md +0 -78
  246. data/lib/solidus_admin/tailwindcss.rb +0 -58
  247. data/lib/tasks/tailwindcss.rake +0 -55
  248. /data/app/components/solidus_admin/{sidebar/account_nav → layout/navigation/account}/component.yml +0 -0
  249. /data/app/components/solidus_admin/{sidebar → layout/navigation}/component.js +0 -0
  250. /data/app/components/solidus_admin/{sidebar → layout/navigation}/component.yml +0 -0
  251. /data/app/components/solidus_admin/{skip_link → layout/skip_link}/component.yml +0 -0
@@ -2,65 +2,65 @@
2
2
 
3
3
  class SolidusAdmin::UI::Button::Component < SolidusAdmin::BaseComponent
4
4
  SIZES = {
5
- s: %w[
5
+ s: %{
6
6
  h-7 w-7 p-1
7
7
  text-xs font-semibold leading-none
8
- ],
9
- m: %w[
8
+ },
9
+ m: %{
10
10
  h-9 w-9 p-1.5
11
11
  text-sm font-semibold leading-none
12
- ],
13
- l: %w[
12
+ },
13
+ l: %{
14
14
  h-12 w-12 p-2
15
15
  text-base font-semibold leading-none
16
- ],
16
+ },
17
17
  }
18
18
 
19
19
  TEXT_PADDINGS = {
20
- s: %w[px-1.5 w-auto],
21
- m: %w[px-3 w-auto],
22
- l: %w[px-4 w-auto],
20
+ s: %{px-1.5 w-auto},
21
+ m: %{px-3 w-auto},
22
+ l: %{px-4 w-auto},
23
23
  }
24
24
 
25
25
  ICON_SIZES = {
26
- s: %w[w-[1.4em] h-[1.4em]],
27
- m: %w[w-[1.35em] h-[1.35em]],
28
- l: %w[w-[1.5em] h-[1.5em]],
26
+ s: %{w-[1.4em] h-[1.4em]},
27
+ m: %{w-[1.35em] h-[1.35em]},
28
+ l: %{w-[1.5em] h-[1.5em]},
29
29
  }
30
30
 
31
31
  SCHEMES = {
32
- primary: %w[
32
+ primary: %{
33
33
  text-white bg-black
34
34
  hover:text-white hover:bg-gray-600
35
- active:text-white active:bg-gray-800
35
+ active:text-white active:bg-gray-800 aria-current:text-white aria-current:bg-gray-800
36
36
  focus:text-white focus:bg-gray-700
37
- disabled:text-gray-400 disabled:bg-gray-100 disabled:cursor-not-allowed
38
- aria-disabled:text-gray-400 aria-disabled:bg-gray-100 aria-disabled:aria-disabled:cursor-not-allowed
39
- ],
40
- secondary: %w[
37
+ disabled:text-gray-400 disabled:bg-gray-100
38
+ aria-disabled:text-gray-400 aria-disabled:bg-gray-100
39
+ },
40
+ secondary: %{
41
41
  text-gray-700 bg-white border border-1 border-gray-200
42
42
  hover:bg-gray-50
43
- active:bg-gray-100
43
+ active:bg-gray-100 aria-current:bg-gray-100
44
44
  focus:bg-gray-50
45
- disabled:text-gray-300 disabled:bg-white disabled:cursor-not-allowed
46
- aria-disabled:text-gray-300 aria-disabled:bg-white aria-disabled:cursor-not-allowed
47
- ],
48
- danger: %w[
45
+ disabled:text-gray-300 disabled:bg-white
46
+ aria-disabled:text-gray-300 aria-disabled:bg-white
47
+ },
48
+ danger: %{
49
49
  text-red-500 bg-white border border-1 border-red-500
50
50
  hover:bg-red-500 hover:border-red-600 hover:text-white
51
- active:bg-red-600 active:border-red-700 active:text-white
51
+ active:bg-red-600 active:border-red-700 active:text-white aria-current:bg-red-600 aria-current:border-red-700 aria-current:text-white
52
52
  focus:bg-red-50 focus:bg-red-500 focus:border-red-600 focus:text-white
53
- disabled:text-red-300 disabled:bg-white disabled:border-red-200 disabled:cursor-not-allowed
54
- aria-disabled:text-red-300 aria-disabled:bg-white aria-disabled:border-red-200 aria-disabled:cursor-not-allowed
55
- ],
56
- ghost: %w[
53
+ disabled:text-red-300 disabled:bg-white disabled:border-red-200
54
+ aria-disabled:text-red-300 aria-disabled:bg-white aria-disabled:border-red-200
55
+ },
56
+ ghost: %{
57
57
  text-gray-700 bg-transparent
58
58
  hover:bg-gray-50
59
- active:bg-gray-100
59
+ active:bg-gray-100 aria-current:bg-gray-100
60
60
  focus:bg-gray-50 focus:ring-gray-300 focus:ring-2
61
- disabled:text-gray-300 disabled:bg-transparent disabled:border-gray-300 disabled:cursor-not-allowed
62
- aria-disabled:text-gray-300 aria-disabled:bg-transparent aria-disabled:border-gray-300 aria-disabled:cursor-not-allowed
63
- ],
61
+ disabled:text-gray-300 disabled:bg-transparent disabled:border-gray-300
62
+ aria-disabled:text-gray-300 aria-disabled:bg-transparent aria-disabled:border-gray-300
63
+ },
64
64
  }
65
65
 
66
66
  def initialize(
@@ -0,0 +1,10 @@
1
+ <div class="<%= stimulus_id %>">
2
+ <ul class="text-sm">
3
+ <% @items.each do |item| %>
4
+ <li class="flex justify-between py-2 <%= item[:class] %>">
5
+ <span><%= item[:label] %></span>
6
+ <span><%= item[:value] %></span>
7
+ </li>
8
+ <% end %>
9
+ </ul>
10
+ </div>
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusAdmin::UI::DetailsList::Component < SolidusAdmin::BaseComponent
4
+ def initialize(items:)
5
+ @items = items
6
+ end
7
+ end
@@ -0,0 +1,50 @@
1
+ <details
2
+ <%= tag.attributes @attributes %>
3
+ >
4
+ <summary
5
+ class="
6
+ text-black
7
+ hover:fill-gray-500
8
+ [[open]_&]:fill-gray-500
9
+ cursor-pointer
10
+ flex
11
+ items-center
12
+ "
13
+ title="<%= @text || t(".more") %>"
14
+ data-action="keydown.esc-><%= stimulus_id %>#close"
15
+ >
16
+ <% if @text %>
17
+ <%= @text %>
18
+ <%= icon_tag "arrow-down-s-fill", class: SIZES.fetch(@size) %>
19
+ <% else %>
20
+ <%= icon_tag "more-line", class: SIZES.fetch(@size) %>
21
+ <% end %>
22
+ </summary>
23
+
24
+ <div
25
+ class="
26
+ absolute
27
+ border
28
+ border-gray-100
29
+ mt-0.5
30
+ flex
31
+ flex-col
32
+ min-w-[10rem]
33
+ p-2
34
+ rounded-sm
35
+ shadow-lg
36
+ bg-white
37
+ z-10
38
+
39
+ <%= DIRECTIONS.fetch(@direction) %>
40
+
41
+ [&>*]:p-2
42
+ [&>*]:rounded-sm
43
+ [&>*:hover]:bg-gray-50
44
+ [&>*]:text-black
45
+ [&>*]:min-w-fit
46
+ "
47
+ >
48
+ <%= content %>
49
+ </div>
50
+ </details>
@@ -0,0 +1,16 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+ import { useClickOutside } from 'stimulus-use'
3
+
4
+ export default class extends Controller {
5
+ connect() {
6
+ useClickOutside(this)
7
+ }
8
+
9
+ clickOutside() {
10
+ this.close()
11
+ }
12
+
13
+ close() {
14
+ this.element.removeAttribute('open')
15
+ }
16
+ }
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusAdmin::UI::Dropdown::Component < SolidusAdmin::BaseComponent
4
+ DIRECTIONS = {
5
+ left: "right-0",
6
+ right: "left-0",
7
+ }
8
+
9
+ SIZES = {
10
+ s: "w-5 h-5",
11
+ m: "w-[22px] h-[22px]",
12
+ }
13
+
14
+ def initialize(text: nil, size: :m, direction: :left, **attributes)
15
+ @text = text
16
+ @size = size
17
+ @attributes = attributes
18
+ @direction = direction
19
+
20
+ @attributes[:"data-controller"] = "#{stimulus_id} #{attributes[:"data-controller"]}"
21
+ @attributes[:"data-action"] = "turbo:before-cache@window->#{stimulus_id}#close #{attributes[:"data-action"]}"
22
+ @attributes[:class] = "
23
+ font-normal
24
+ #{@size == :m ? 'text-base' : 'text-sm'}
25
+ #{@attributes[:class]}
26
+ "
27
+ end
28
+ end
@@ -0,0 +1,2 @@
1
+ en:
2
+ more: "More"
@@ -0,0 +1,36 @@
1
+ <fieldset class="<%= stimulus_id %>"
2
+ data-controller="<%= stimulus_id %>"
3
+ <%= :disabled if @disabled %>
4
+ >
5
+ <div class="<%= stimulus_id %>--address-form flex flex-wrap gap-4 pb-4">
6
+ <%= render component("ui/forms/field").text_field(@name, :name, object: @address) %>
7
+ <%= render component("ui/forms/field").text_field(@name, :address1, object: @address) %>
8
+ <%= render component("ui/forms/field").text_field(@name, :address2, object: @address) %>
9
+ <div class="flex gap-4 w-full">
10
+ <%= render component("ui/forms/field").text_field(@name, :city, object: @address) %>
11
+ <%= render component("ui/forms/field").text_field(@name, :zipcode, object: @address) %>
12
+ </div>
13
+
14
+ <%= render component("ui/forms/field").select(
15
+ @name,
16
+ :country_id,
17
+ Spree::Country.all.map { |c| [c.name, c.id] },
18
+ object: @address,
19
+ value: @address.try(:country_id),
20
+ "data-#{stimulus_id}-target": "country",
21
+ "data-action": "change->#{stimulus_id}#loadStates"
22
+ ) %>
23
+
24
+ <%= render component("ui/forms/field").select(
25
+ @name,
26
+ :state_id,
27
+ state_options,
28
+ object: @address,
29
+ value: @address.try(:state_id),
30
+ disabled: @address.country&.states&.empty?,
31
+ "data-#{stimulus_id}-target": "state"
32
+ ) %>
33
+
34
+ <%= render component("ui/forms/field").text_field(@name, :phone, object: @address) %>
35
+ </div>
36
+ </fieldset>
@@ -0,0 +1,34 @@
1
+ import { Controller } from '@hotwired/stimulus'
2
+
3
+ export default class extends Controller {
4
+ static targets = ["country", "state"]
5
+
6
+ loadStates() {
7
+ const countryId = this.countryTarget.value
8
+
9
+ fetch(`/admin/countries/${countryId}/states`)
10
+ .then(response => response.json())
11
+ .then(data => {
12
+ this.updateStateOptions(data)
13
+ })
14
+ }
15
+
16
+ updateStateOptions(data) {
17
+ const stateSelect = this.stateTarget
18
+
19
+ stateSelect.innerHTML = ""
20
+
21
+ if (data.length === 0) {
22
+ stateSelect.disabled = true
23
+ } else {
24
+ stateSelect.disabled = false
25
+
26
+ data.forEach((state) => {
27
+ const option = document.createElement("option")
28
+ option.value = state.id
29
+ option.innerText = state.name
30
+ stateSelect.appendChild(option)
31
+ })
32
+ }
33
+ }
34
+ }
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SolidusAdmin::UI::Forms::Address::Component < SolidusAdmin::BaseComponent
4
+ def initialize(address:, name:, disabled: false)
5
+ @address = address
6
+ @name = name
7
+ @disabled = disabled
8
+ end
9
+
10
+ def state_options
11
+ return [] unless @address.country
12
+ @address.country.states.map { |s| [s.name, s.id] }
13
+ end
14
+ end
@@ -2,8 +2,7 @@
2
2
  <div class="flex gap-1 items-center">
3
3
  <span class="
4
4
  text-gray-700
5
- body-tiny-bold
6
- body-text-xs-semibold
5
+ font-semibold text-xs
7
6
  "><%= @label %></span>
8
7
 
9
8
  <%= render component('ui/toggletip').new(text: @tip) if @tip.present? %>
@@ -11,18 +10,20 @@
11
10
 
12
11
  <% if @input_attributes.present? %>
13
12
  <%= render component('ui/forms/input').new(**@input_attributes) %>
13
+ <% elsif content.respond_to?(:render_in) %>
14
+ <%= render content %>
14
15
  <% else %>
15
16
  <%= content %>
16
17
  <% end %>
17
18
 
18
19
  <% if @hint.present? || @error.present? %>
19
20
  <div class="
20
- body-tiny
21
+ font-normal text-xs
21
22
  [:disabled~&]:text-gray-300 text-gray-500
22
23
  flex gap-1 flex-col
23
24
  ">
24
25
  <%= tag.span @hint if @hint.present? %>
25
- <%= tag.span safe_join(@error, tag.br), class: "text-red-400" if @error.present? %>
26
+ <%= tag.span safe_join(@error, tag.br), class: "text-red-600" if @error.present? %>
26
27
  </div>
27
28
  <% end %>
28
29
  </label>
@@ -1,6 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class SolidusAdmin::UI::Forms::Field::Component < SolidusAdmin::BaseComponent
4
+ extend SolidusAdmin::ComponentsHelper
5
+
4
6
  def initialize(label:, hint: nil, tip: nil, error: nil, input_attributes: nil, **attributes)
5
7
  @label = label
6
8
  @hint = hint
@@ -12,61 +14,97 @@ class SolidusAdmin::UI::Forms::Field::Component < SolidusAdmin::BaseComponent
12
14
  raise ArgumentError, "provide either a block or input_attributes" if content? && input_attributes
13
15
  end
14
16
 
15
- def self.text_field(form, method, hint: nil, tip: nil, size: :m, **attributes)
16
- errors = form.object.errors.messages_for(method).presence
17
+ def self.text_field(form, method, object: nil, hint: nil, tip: nil, size: :m, **attributes)
18
+ object_name, object, label, errors = extract_form_details(form, object, method)
17
19
 
18
20
  new(
19
- label: form.object.class.human_attribute_name(method),
21
+ label: label,
20
22
  hint: hint,
21
23
  tip: tip,
22
24
  error: errors,
23
25
  input_attributes: {
24
- name: "#{form.object_name}[#{method}]",
26
+ name: "#{object_name}[#{method}]",
25
27
  tag: :input,
26
28
  size: size,
27
- value: form.object.public_send(method),
29
+ value: object.public_send(method),
28
30
  error: (errors.to_sentence.capitalize if errors),
29
31
  **attributes,
30
32
  }
31
33
  )
32
34
  end
33
35
 
34
- def self.select(form, method, choices, hint: nil, tip: nil, size: :m, **attributes)
35
- errors = form.object.errors.messages_for(method).presence
36
+ def self.select(form, method, choices, object: nil, hint: nil, tip: nil, size: :m, **attributes)
37
+ object_name, object, label, errors = extract_form_details(form, object, method)
36
38
 
37
39
  new(
38
- label: form.object.class.human_attribute_name(method),
40
+ label: label,
39
41
  hint: hint,
40
42
  tip: tip,
41
43
  error: errors,
42
44
  input_attributes: {
43
- name: "#{form.object_name}[#{method}]",
45
+ name: "#{object_name}[#{method}]",
44
46
  tag: :select,
45
47
  choices: choices,
46
48
  size: size,
47
- value: form.object.public_send(method),
49
+ value: object.public_send(method),
48
50
  error: (errors.to_sentence.capitalize if errors),
49
51
  **attributes,
50
52
  }
51
53
  )
52
54
  end
53
55
 
54
- def self.text_area(form, method, hint: nil, tip: nil, size: :m, **attributes)
55
- errors = form.object.errors.messages_for(method).presence
56
+ def self.text_area(form, method, object: nil, hint: nil, tip: nil, size: :m, **attributes)
57
+ object_name, object, label, errors = extract_form_details(form, object, method)
56
58
 
57
59
  new(
58
- label: form.object.class.human_attribute_name(method),
60
+ label: label,
59
61
  hint: hint,
60
62
  tip: tip,
61
63
  error: errors,
62
64
  input_attributes: {
63
- name: "#{form.object_name}[#{method}]",
65
+ name: "#{object_name}[#{method}]",
64
66
  size: size,
65
67
  tag: :textarea,
66
- value: form.object.public_send(method),
68
+ value: object.public_send(method),
67
69
  error: (errors.to_sentence.capitalize if errors),
68
70
  **attributes,
69
71
  }
70
72
  )
71
73
  end
74
+
75
+ def self.toggle(form, method, object: nil, hint: nil, tip: nil, size: :m, **attributes)
76
+ object_name, object, label, errors = extract_form_details(form, object, method)
77
+
78
+ new(
79
+ label: label,
80
+ hint: hint,
81
+ tip: tip,
82
+ error: errors,
83
+ ).with_content(
84
+ component('ui/forms/switch').new(
85
+ name: "#{object_name}[#{method}]",
86
+ size: size,
87
+ checked: object.public_send(method),
88
+ include_hidden: true,
89
+ **attributes,
90
+ )
91
+ )
92
+ end
93
+
94
+ def self.extract_form_details(form, object, method)
95
+ if form.is_a?(String)
96
+ object_name = form
97
+ raise ArgumentError, "Object must be provided when form name is a string" unless object
98
+ elsif form.respond_to?(:object)
99
+ object_name = form.object_name
100
+ object = form.object
101
+ else
102
+ raise ArgumentError, "Invalid arguments: expected a form object or form.object_name and form.object"
103
+ end
104
+
105
+ errors = object.errors.messages_for(method).presence if object.respond_to?(:errors)
106
+ label = object.class.human_attribute_name(method)
107
+
108
+ [object_name, object, label, errors]
109
+ end
72
110
  end
@@ -2,9 +2,9 @@
2
2
 
3
3
  class SolidusAdmin::UI::Forms::Input::Component < SolidusAdmin::BaseComponent
4
4
  SIZES = {
5
- s: "form-control-sm px-3 py-1.5 body-small",
6
- m: "form-control-md px-3 py-1.5 body-small",
7
- l: "form-control-lg px-3 py-1.5 body-text"
5
+ s: "form-control-sm px-3 py-1.5 font-normal text-sm",
6
+ m: "form-control-md px-3 py-1.5 font-normal text-sm",
7
+ l: "form-control-lg px-3 py-1.5 font-normal text-base"
8
8
  }.freeze
9
9
 
10
10
  HEIGHTS = {
@@ -32,6 +32,7 @@ class SolidusAdmin::UI::Forms::Input::Component < SolidusAdmin::BaseComponent
32
32
  datetime-local
33
33
  month
34
34
  week
35
+ search
35
36
  time
36
37
  ]).freeze
37
38
 
@@ -39,16 +40,21 @@ class SolidusAdmin::UI::Forms::Input::Component < SolidusAdmin::BaseComponent
39
40
  raise ArgumentError, "unsupported tag: #{tag}" unless %i[input textarea select].include?(tag)
40
41
 
41
42
  specialized_classes = []
43
+ readonly_classes = "read-only:bg-gray-15 focus:read-only:bg-gray-15 focus:read-only:ring-0
44
+ read-only:cursor-not-allowed read-only:focus:border-gray-300
45
+ read-only:hover:border-gray-300 read-only:hover:focus:border-gray-300"
42
46
 
43
47
  case tag
44
48
  when :input
45
49
  specialized_classes << "form-input"
50
+ specialized_classes << readonly_classes
46
51
  specialized_classes << HEIGHTS[size]
47
52
  if attributes[:type] && !TYPES.include?(attributes[:type])
48
53
  raise ArgumentError, "unsupported type attribute: #{attributes[:type]}"
49
54
  end
50
55
  when :textarea
51
56
  specialized_classes << "form-textarea"
57
+ specialized_classes << readonly_classes
52
58
  specialized_classes << MULTILINE_HEIGHTS[size]
53
59
  when :select
54
60
  if attributes[:multiple]
@@ -68,8 +74,8 @@ class SolidusAdmin::UI::Forms::Input::Component < SolidusAdmin::BaseComponent
68
74
  hover:border-gray-500
69
75
  focus:ring focus:ring-gray-300 focus:ring-0.5 focus:bg-white focus:ring-offset-0 [&:focus-visible]:outline-none
70
76
  disabled:bg-gray-50 disabled:text-gray-500 disabled:placeholder:text-gray-300 disabled:cursor-not-allowed
71
- invalid:border-red-400 invalid:hover:border-red-400 invalid:text-red-400
72
- aria-invalid:border-red-400 aria-invalid:hover:border-red-400 aria-invalid:text-red-400
77
+ invalid:border-red-600 invalid:hover:border-red-600 invalid:text-red-600
78
+ aria-invalid:border-red-600 aria-invalid:hover:border-red-600 aria-invalid:text-red-600
73
79
  ],
74
80
  SIZES[size],
75
81
  specialized_classes,
@@ -0,0 +1,52 @@
1
+ <div
2
+ data-controller="<%= stimulus_id %>"
3
+ class="w-full relative overflow-visible"
4
+ data-action="
5
+ keydown.up-><%= stimulus_id %>#selectPrev
6
+ keydown.down-><%= stimulus_id %>#selectNext
7
+ keydown.enter-><%= stimulus_id %>#selectResult
8
+ "
9
+ data-<%= stimulus_id %>-loading-text-value="<%= t('.loading') %>"
10
+ data-<%= stimulus_id %>-initial-text-value="<%= t('.initial') %>"
11
+ data-<%= stimulus_id %>-empty-text-value="<%= t('.empty') %>"
12
+ >
13
+ <div>
14
+ <div class="peer">
15
+ <%= render component("ui/forms/search_field").new(
16
+ id: "#{stimulus_id}--search-field--#{@id}",
17
+ "data-action": "
18
+ #{stimulus_id}#search
19
+ #{stimulus_id}#showResults
20
+ ",
21
+ "data-#{stimulus_id}-target": "searchField",
22
+ **@attributes,
23
+ ) %>
24
+ </div>
25
+
26
+ <details class="px-6 relative overflow-visible">
27
+ <summary class="hidden"></summary>
28
+ <div
29
+ class="
30
+ absolute
31
+ left-0
32
+ top-2
33
+ bg-white
34
+ z-30
35
+ w-full
36
+ rounded-lg
37
+ shadow
38
+ border
39
+ border-gray-100
40
+ p-2
41
+ flex
42
+ flex-col
43
+ gap-1
44
+ max-h-screen
45
+ overflow-y-auto
46
+ "
47
+ data-<%= stimulus_id %>-target="results"
48
+ >
49
+ </div>
50
+ </details>
51
+ </div>
52
+ </div>
@@ -0,0 +1,116 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { useClickOutside, useDebounce } from "stimulus-use"
3
+
4
+ export default class extends Controller {
5
+ static targets = ["result", "results", "searchField"]
6
+ static values = {
7
+ results: String,
8
+ loadingText: String,
9
+ initialText: String,
10
+ emptyText: String,
11
+ }
12
+ static debounces = ["search"]
13
+
14
+ get query() {
15
+ return this.searchFieldTarget.value
16
+ }
17
+
18
+ get selectedResult() {
19
+ // Keep the index within boundaries
20
+ if (this.selectedIndex < 0) this.selectedIndex = 0
21
+ if (this.selectedIndex >= this.resultTargets.length) this.selectedIndex = this.resultTargets.length - 1
22
+
23
+ return this.resultTargets[this.selectedIndex]
24
+ }
25
+
26
+ connect() {
27
+ useClickOutside(this)
28
+ useDebounce(this)
29
+
30
+ this.selectedIndex = 0
31
+
32
+ if (this.query) {
33
+ this.showResults()
34
+ this.search()
35
+ }
36
+ }
37
+
38
+ selectResult(event) {
39
+ event.preventDefault()
40
+ this.dispatch("submit", { detail: { resultTarget: this.selectedResult } })
41
+ }
42
+
43
+ clickedResult(event) {
44
+ this.selectedIndex = this.resultTargets.indexOf(event.currentTarget)
45
+ this.render()
46
+ this.selectResult(event)
47
+ }
48
+
49
+ selectPrev(event) {
50
+ event.preventDefault()
51
+ this.selectedIndex -= 1
52
+ this.render()
53
+ }
54
+
55
+ selectNext(event) {
56
+ event.preventDefault()
57
+ this.selectedIndex += 1
58
+ this.render()
59
+ }
60
+
61
+ clickOutside() {
62
+ this.openResults = false
63
+ this.render()
64
+ }
65
+
66
+ async search() {
67
+ const query = this.query
68
+
69
+ if (query) {
70
+ this.resultsValue = this.loadingTextValue
71
+ this.render()
72
+ this.dispatch("search", { detail: { query, controller: this } })
73
+ } else {
74
+ this.resultsValue = this.initialTextValue
75
+ this.render()
76
+ }
77
+ }
78
+
79
+ resultsValueChanged() {
80
+ this.selectedIndex = 0
81
+ this.render()
82
+ }
83
+
84
+ showResults() {
85
+ this.openResults = true
86
+ this.render()
87
+ }
88
+
89
+ render() {
90
+ let resultsHtml = this.resultsValue
91
+
92
+ if (this.renderedHtml !== resultsHtml) {
93
+ this.renderedHtml = resultsHtml
94
+ this.resultsTarget.innerHTML = resultsHtml
95
+ }
96
+
97
+ if (this.openResults && resultsHtml && this.query) {
98
+ if (!this.resultsTarget.parentNode.open) this.selectedIndex = 0
99
+
100
+ for (const result of this.resultTargets) {
101
+ if (result === this.selectedResult) {
102
+ if (!result.hasAttribute("aria-selected") && result.scrollIntoViewIfNeeded) {
103
+ // This is a non-standard method, but it's supported by all major browsers
104
+ result.scrollIntoViewIfNeeded()
105
+ }
106
+ result.setAttribute("aria-selected", true)
107
+ } else {
108
+ result.removeAttribute("aria-selected")
109
+ }
110
+ }
111
+ this.resultsTarget.parentNode.open = true
112
+ } else {
113
+ this.resultsTarget.parentNode.open = false
114
+ }
115
+ }
116
+ }