@spree/docs 0.1.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 (183) hide show
  1. package/README.md +54 -0
  2. package/dist/api-reference/platform/authentication.md +38 -0
  3. package/dist/api-reference/store-api/authentication.md +188 -0
  4. package/dist/api-reference/store-api/errors.md +277 -0
  5. package/dist/api-reference/store-api/idempotency.md +129 -0
  6. package/dist/api-reference/store-api/introduction.md +34 -0
  7. package/dist/api-reference/store-api/localization.md +279 -0
  8. package/dist/api-reference/store-api/metadata.md +160 -0
  9. package/dist/api-reference/store-api/monetary-amounts.md +65 -0
  10. package/dist/api-reference/store-api/querying.md +399 -0
  11. package/dist/api-reference/store-api/rate-limitting.md +103 -0
  12. package/dist/api-reference/store-api/relations.md +185 -0
  13. package/dist/api-reference/storefront/authentication.md +88 -0
  14. package/dist/api-reference/tutorials/adyen-integration-guide-for-android.md +165 -0
  15. package/dist/api-reference/tutorials/adyen-integration-guide-for-ios.md +194 -0
  16. package/dist/api-reference/tutorials/quick-checkout-with-stripe.md +248 -0
  17. package/dist/api-reference/v2/fetching-multiple-resources.md +26 -0
  18. package/dist/api-reference/v2/filtering-and-sorting.md +53 -0
  19. package/dist/api-reference/v2/introduction.md +22 -0
  20. package/dist/api-reference/v2/pagination.md +37 -0
  21. package/dist/api-reference/webhooks-events.md +883 -0
  22. package/dist/developer/admin/admin.md +205 -0
  23. package/dist/developer/admin/authentication.md +59 -0
  24. package/dist/developer/admin/components.md +711 -0
  25. package/dist/developer/admin/custom-css.md +243 -0
  26. package/dist/developer/admin/custom-javascript.md +116 -0
  27. package/dist/developer/admin/extending-ui.md +1964 -0
  28. package/dist/developer/admin/form-builder.md +444 -0
  29. package/dist/developer/admin/helper-methods.md +531 -0
  30. package/dist/developer/admin/navigation.md +805 -0
  31. package/dist/developer/admin/tables.md +491 -0
  32. package/dist/developer/advanced/adding_spree_to_rails_app.md +106 -0
  33. package/dist/developer/cli/quickstart.md +137 -0
  34. package/dist/developer/contributing/creating-an-extension.md +258 -0
  35. package/dist/developer/contributing/developing-spree.md +339 -0
  36. package/dist/developer/contributing/quickstart.md +32 -0
  37. package/dist/developer/contributing/updating-extensions.md +67 -0
  38. package/dist/developer/core-concepts/addresses.md +265 -0
  39. package/dist/developer/core-concepts/adjustments.md +107 -0
  40. package/dist/developer/core-concepts/architecture.md +177 -0
  41. package/dist/developer/core-concepts/calculators.md +323 -0
  42. package/dist/developer/core-concepts/customers.md +230 -0
  43. package/dist/developer/core-concepts/events.md +624 -0
  44. package/dist/developer/core-concepts/imports-exports.md +698 -0
  45. package/dist/developer/core-concepts/inventory.md +191 -0
  46. package/dist/developer/core-concepts/markets.md +250 -0
  47. package/dist/developer/core-concepts/media.md +167 -0
  48. package/dist/developer/core-concepts/metafields.md +187 -0
  49. package/dist/developer/core-concepts/orders.md +328 -0
  50. package/dist/developer/core-concepts/payments.md +710 -0
  51. package/dist/developer/core-concepts/pricing.md +163 -0
  52. package/dist/developer/core-concepts/products.md +360 -0
  53. package/dist/developer/core-concepts/promotions.md +322 -0
  54. package/dist/developer/core-concepts/reports.md +206 -0
  55. package/dist/developer/core-concepts/search-filtering.md +237 -0
  56. package/dist/developer/core-concepts/shipments.md +212 -0
  57. package/dist/developer/core-concepts/slugs.md +111 -0
  58. package/dist/developer/core-concepts/staff-roles.md +123 -0
  59. package/dist/developer/core-concepts/store-credits-gift-cards.md +317 -0
  60. package/dist/developer/core-concepts/stores.md +117 -0
  61. package/dist/developer/core-concepts/taxes.md +135 -0
  62. package/dist/developer/core-concepts/translations.md +120 -0
  63. package/dist/developer/core-concepts/users.md +299 -0
  64. package/dist/developer/core-concepts/webhooks.md +378 -0
  65. package/dist/developer/create-spree-app/quickstart.md +158 -0
  66. package/dist/developer/customization/api.md +93 -0
  67. package/dist/developer/customization/authentication.md +88 -0
  68. package/dist/developer/customization/checkout.md +204 -0
  69. package/dist/developer/customization/configuration.md +55 -0
  70. package/dist/developer/customization/decorators.md +523 -0
  71. package/dist/developer/customization/dependencies.md +232 -0
  72. package/dist/developer/customization/emails.md +21 -0
  73. package/dist/developer/customization/extensions.md +92 -0
  74. package/dist/developer/customization/metadata.md +236 -0
  75. package/dist/developer/customization/model-preferences.md +130 -0
  76. package/dist/developer/customization/permissions.md +265 -0
  77. package/dist/developer/customization/quickstart.md +229 -0
  78. package/dist/developer/customization/routes.md +24 -0
  79. package/dist/developer/customization/v4/admin-panel.md +78 -0
  80. package/dist/developer/customization/v4/authentication.md +210 -0
  81. package/dist/developer/customization/v4/checkout.md +212 -0
  82. package/dist/developer/customization/v4/deface.md +251 -0
  83. package/dist/developer/customization/v4/images.md +86 -0
  84. package/dist/developer/customization/v4/storefront.md +450 -0
  85. package/dist/developer/deployment/assets.md +87 -0
  86. package/dist/developer/deployment/aws.md +335 -0
  87. package/dist/developer/deployment/caching.md +27 -0
  88. package/dist/developer/deployment/cdn.md +39 -0
  89. package/dist/developer/deployment/database.md +155 -0
  90. package/dist/developer/deployment/docker.md +128 -0
  91. package/dist/developer/deployment/emails.md +77 -0
  92. package/dist/developer/deployment/environment_variables.md +111 -0
  93. package/dist/developer/deployment/heroku.md +51 -0
  94. package/dist/developer/deployment/render.md +95 -0
  95. package/dist/developer/getting-started/quickstart.md +82 -0
  96. package/dist/developer/how-to/custom-payment-method.md +374 -0
  97. package/dist/developer/how-to/custom-promotion.md +373 -0
  98. package/dist/developer/how-to/custom-report.md +387 -0
  99. package/dist/developer/how-to/custom-search-provider.md +230 -0
  100. package/dist/developer/multi-store/quickstart.md +71 -0
  101. package/dist/developer/multi-store/setup.md +38 -0
  102. package/dist/developer/multi-tenant/configuration.md +41 -0
  103. package/dist/developer/multi-tenant/core-concepts.md +75 -0
  104. package/dist/developer/multi-tenant/installation.md +96 -0
  105. package/dist/developer/multi-tenant/quickstart.md +20 -0
  106. package/dist/developer/multi-vendor/installation.md +45 -0
  107. package/dist/developer/multi-vendor/quickstart.md +17 -0
  108. package/dist/developer/sdk/admin/quickstart.md +22 -0
  109. package/dist/developer/sdk/authentication.md +89 -0
  110. package/dist/developer/sdk/configuration.md +225 -0
  111. package/dist/developer/sdk/quickstart.md +82 -0
  112. package/dist/developer/sdk/store/account.md +67 -0
  113. package/dist/developer/sdk/store/cart-checkout.md +140 -0
  114. package/dist/developer/sdk/store/markets.md +151 -0
  115. package/dist/developer/sdk/store/payments.md +96 -0
  116. package/dist/developer/sdk/store/products.md +149 -0
  117. package/dist/developer/sdk/store/wishlists.md +52 -0
  118. package/dist/developer/security/pci_compliance.md +15 -0
  119. package/dist/developer/security/security_policy.md +68 -0
  120. package/dist/developer/storefront/blocks.md +285 -0
  121. package/dist/developer/storefront/custom-css.md +260 -0
  122. package/dist/developer/storefront/custom-javascript.md +166 -0
  123. package/dist/developer/storefront/helper-methods.md +1288 -0
  124. package/dist/developer/storefront/links.md +298 -0
  125. package/dist/developer/storefront/nextjs/architecture.md +150 -0
  126. package/dist/developer/storefront/nextjs/customization.md +141 -0
  127. package/dist/developer/storefront/nextjs/deployment.md +180 -0
  128. package/dist/developer/storefront/nextjs/quickstart.md +92 -0
  129. package/dist/developer/storefront/nextjs/spree-next-package.md +314 -0
  130. package/dist/developer/storefront/pages.md +163 -0
  131. package/dist/developer/storefront/sections.md +569 -0
  132. package/dist/developer/storefront/storefront.md +56 -0
  133. package/dist/developer/storefront/themes.md +161 -0
  134. package/dist/developer/tutorial/admin.md +134 -0
  135. package/dist/developer/tutorial/extending-models.md +380 -0
  136. package/dist/developer/tutorial/file-uploads.md +121 -0
  137. package/dist/developer/tutorial/introduction.md +33 -0
  138. package/dist/developer/tutorial/model.md +41 -0
  139. package/dist/developer/tutorial/page-builder.md +487 -0
  140. package/dist/developer/tutorial/rich-text.md +73 -0
  141. package/dist/developer/tutorial/seo.md +332 -0
  142. package/dist/developer/tutorial/storefront.md +352 -0
  143. package/dist/developer/tutorial/testing.md +558 -0
  144. package/dist/developer/upgrades/2.0-to-2.1.md +46 -0
  145. package/dist/developer/upgrades/2.1-to-2.2.md +59 -0
  146. package/dist/developer/upgrades/2.2-to-2.3.md +44 -0
  147. package/dist/developer/upgrades/2.3-to-2.4.md +42 -0
  148. package/dist/developer/upgrades/3.0-to-3.1.md +47 -0
  149. package/dist/developer/upgrades/3.1-to-3.2.md +34 -0
  150. package/dist/developer/upgrades/3.2-to-3.3.md +70 -0
  151. package/dist/developer/upgrades/3.3-to-3.4.md +36 -0
  152. package/dist/developer/upgrades/3.4-to-3.5.md +44 -0
  153. package/dist/developer/upgrades/3.5-to-3.6.md +40 -0
  154. package/dist/developer/upgrades/3.6-to-3.7.md +62 -0
  155. package/dist/developer/upgrades/3.7-to-4.0.md +152 -0
  156. package/dist/developer/upgrades/4.0-to-4.1.md +92 -0
  157. package/dist/developer/upgrades/4.1-to-4.2.md +109 -0
  158. package/dist/developer/upgrades/4.10-to-5.0.md +129 -0
  159. package/dist/developer/upgrades/4.2-to-4.3.md +100 -0
  160. package/dist/developer/upgrades/4.3-to-4.4.md +125 -0
  161. package/dist/developer/upgrades/4.4-to-4.5.md +94 -0
  162. package/dist/developer/upgrades/4.5-to-4.6.md +119 -0
  163. package/dist/developer/upgrades/4.6-to-4.7.md +39 -0
  164. package/dist/developer/upgrades/4.8-to-4.9.md +24 -0
  165. package/dist/developer/upgrades/4.9-to-4.10.md +24 -0
  166. package/dist/developer/upgrades/4.x-to-4.8.md +52 -0
  167. package/dist/developer/upgrades/5.0-to-5.1.md +28 -0
  168. package/dist/developer/upgrades/5.1-to-5.2.md +127 -0
  169. package/dist/developer/upgrades/5.2-to-5.3.md +338 -0
  170. package/dist/developer/upgrades/5.3-to-5.4.md +248 -0
  171. package/dist/developer/upgrades/quickstart.md +36 -0
  172. package/dist/integrations/analytics/google-analytics.md +64 -0
  173. package/dist/integrations/analytics/google-tag-manager.md +78 -0
  174. package/dist/integrations/integrations.md +39 -0
  175. package/dist/integrations/marketing/klaviyo.md +99 -0
  176. package/dist/integrations/payments/adyen.md +90 -0
  177. package/dist/integrations/payments/paypal.md +41 -0
  178. package/dist/integrations/payments/razorpay.md +45 -0
  179. package/dist/integrations/payments/stripe.md +109 -0
  180. package/dist/integrations/search/meilisearch.md +236 -0
  181. package/dist/integrations/sso-mfa-social-login/admin-dashboard.md +57 -0
  182. package/dist/integrations/sso-mfa-social-login/storefront.md +56 -0
  183. package/package.json +27 -0
@@ -0,0 +1,711 @@
1
+ ---
2
+ title: Admin Components
3
+ sidebarTitle: Components
4
+ ---
5
+
6
+ Spree Admin provides a set of reusable UI components that you can use in your custom admin views. These components are implemented as view helpers and integrate with Stimulus controllers for interactivity.
7
+
8
+ ## Dropdown
9
+
10
+ The dropdown component creates accessible dropdown menus with automatic positioning using Floating UI.
11
+
12
+ ### Basic Usage
13
+
14
+ ```erb
15
+ <%= dropdown do %>
16
+ <%= dropdown_toggle class: 'btn-light btn-sm' do %>
17
+ <%= icon('dots-vertical', class: 'mr-0') %>
18
+ <% end %>
19
+
20
+ <%= dropdown_menu do %>
21
+ <%= link_to_with_icon 'pencil', Spree.t(:edit), edit_path, class: 'dropdown-item' %>
22
+ <%= link_to_with_icon 'trash', Spree.t(:delete), delete_path,
23
+ class: 'dropdown-item text-danger',
24
+ data: { turbo_method: :delete, turbo_confirm: Spree.t(:are_you_sure) } %>
25
+ <% end %>
26
+ <% end %>
27
+ ```
28
+
29
+ ### Features
30
+
31
+ - **Automatic positioning** - Uses Floating UI to position the menu optimally
32
+ - **Auto-flip** - Menu flips to stay within viewport
33
+ - **Click outside to close** - Menu closes when clicking outside
34
+ - **Escape to close** - Menu closes when pressing Escape key
35
+ - **Keyboard navigation** - Full keyboard accessibility
36
+
37
+ ### `dropdown`
38
+
39
+ Creates the dropdown container with Stimulus controller.
40
+
41
+ ```erb
42
+ <%= dropdown do %>
43
+ <!-- toggle and menu -->
44
+ <% end %>
45
+
46
+ <%= dropdown placement: 'top-end' do %>
47
+ <!-- menu opens above, aligned to end -->
48
+ <% end %>
49
+ ```
50
+
51
+ | Option | Type | Default | Description |
52
+ |--------|------|---------|-------------|
53
+ | `class` | String | - | Additional CSS classes |
54
+ | `placement` | String | `bottom-start` | Menu placement: `bottom-start`, `bottom-end`, `top-start`, `top-end` |
55
+ | `direction` | String | - | Legacy option: `left` → `bottom-end`, `top` → `top-start`, `top-left` → `top-end` |
56
+ | `portal` | Boolean | - | Whether to portal the dropdown to body |
57
+ | `data` | Hash | - | Additional data attributes |
58
+
59
+ ### `dropdown_toggle`
60
+
61
+ Creates the button that toggles the dropdown menu.
62
+
63
+ ```erb
64
+ <%= dropdown_toggle class: 'btn-primary' do %>
65
+ Actions <%= icon('chevron-down', class: 'ml-2') %>
66
+ <% end %>
67
+ ```
68
+
69
+ | Option | Type | Default | Description |
70
+ |--------|------|---------|-------------|
71
+ | `class` | String | - | Additional CSS classes (added to `btn` base class) |
72
+ | `data` | Hash | - | Additional data attributes |
73
+
74
+ ### `dropdown_menu`
75
+
76
+ Creates the menu container for dropdown items.
77
+
78
+ ```erb
79
+ <%= dropdown_menu do %>
80
+ <%= link_to 'Option 1', '#', class: 'dropdown-item' %>
81
+ <div class="dropdown-divider"></div>
82
+ <%= link_to 'Option 2', '#', class: 'dropdown-item text-danger' %>
83
+ <% end %>
84
+ ```
85
+
86
+ | Option | Type | Default | Description |
87
+ |--------|------|---------|-------------|
88
+ | `class` | String | - | Additional CSS classes |
89
+ | `data` | Hash | - | Additional data attributes |
90
+
91
+ ### Complete Example
92
+
93
+ ```erb
94
+ <%= content_for :page_actions do %>
95
+ <%= dropdown do %>
96
+ <%= dropdown_toggle class: 'btn-primary' do %>
97
+ <%= icon('settings', class: 'mr-2') %>
98
+ Actions
99
+ <%= icon('chevron-down', class: 'ml-2') %>
100
+ <% end %>
101
+
102
+ <%= dropdown_menu do %>
103
+ <%= link_to_with_icon 'download', 'Export CSV', export_path(format: :csv), class: 'dropdown-item' %>
104
+ <%= link_to_with_icon 'file-export', 'Export Excel', export_path(format: :xlsx), class: 'dropdown-item' %>
105
+ <div class="dropdown-divider"></div>
106
+ <%= link_to_with_icon 'upload', 'Import', import_path, class: 'dropdown-item' %>
107
+ <div class="dropdown-divider"></div>
108
+ <%= link_to_with_icon 'trash', 'Delete All', bulk_delete_path,
109
+ class: 'dropdown-item text-danger',
110
+ data: { turbo_method: :delete, turbo_confirm: Spree.t(:are_you_sure) } %>
111
+ <% end %>
112
+ <% end %>
113
+ <% end %>
114
+ ```
115
+
116
+ ## Dialog
117
+
118
+ Dialogs (modals) are used for focused interactions that require user attention. They overlay the page content and must be dismissed before continuing.
119
+
120
+ ### Basic Usage
121
+
122
+ ```erb
123
+ <div class="dialog" data-controller="dialog">
124
+ <%= dialog_header('Edit Product') %>
125
+
126
+ <div class="dialog-body">
127
+ <!-- Dialog content -->
128
+ </div>
129
+
130
+ <div class="dialog-footer">
131
+ <%= dialog_discard_button %>
132
+ <%= turbo_save_button_tag %>
133
+ </div>
134
+ </div>
135
+ ```
136
+
137
+ ### `dialog_header`
138
+
139
+ Creates a dialog header with title and close button.
140
+
141
+ ```erb
142
+ <%= dialog_header('Confirm Action') %>
143
+ <%= dialog_header('Custom Dialog', 'my-dialog') %>
144
+ ```
145
+
146
+ | Parameter | Type | Default | Description |
147
+ |-----------|------|---------|-------------|
148
+ | `title` | String | required | The dialog title |
149
+ | `controller_name` | String | `dialog` | Stimulus controller name for the close action |
150
+
151
+ **Renders:**
152
+
153
+ ```html
154
+ <div class="dialog-header">
155
+ <h5 class="dialog-title">Confirm Action</h5>
156
+ <button type="button" class="btn-close" data-action="dialog#close" data-dismiss="dialog"></button>
157
+ </div>
158
+ ```
159
+
160
+ ### `dialog_close_button`
161
+
162
+ Creates a standalone close button for dialogs.
163
+
164
+ ```erb
165
+ <%= dialog_close_button %>
166
+ <%= dialog_close_button('custom-controller') %>
167
+ ```
168
+
169
+ | Parameter | Type | Default | Description |
170
+ |-----------|------|---------|-------------|
171
+ | `controller_name` | String | `dialog` | Stimulus controller name |
172
+
173
+ ### `dialog_discard_button`
174
+
175
+ Creates a "Discard" button that closes the dialog.
176
+
177
+ ```erb
178
+ <%= dialog_discard_button %>
179
+ ```
180
+
181
+ | Parameter | Type | Default | Description |
182
+ |-----------|------|---------|-------------|
183
+ | `controller_name` | String | `dialog` | Stimulus controller name |
184
+
185
+ **Renders:**
186
+
187
+ ```html
188
+ <button type="button" class="btn btn-light" data-action="dialog#close" data-dismiss="dialog">
189
+ Discard
190
+ </button>
191
+ ```
192
+
193
+ ### Complete Dialog Example
194
+
195
+ ```erb
196
+ <%= turbo_frame_tag 'main-dialog' do %>
197
+ <div class="dialog-backdrop" data-controller="dialog" data-action="click->dialog#backdropClose keydown.esc@window->dialog#close">
198
+ <div class="dialog">
199
+ <%= dialog_header('Add New Item') %>
200
+
201
+ <%= form_with model: @item, url: items_path, data: { turbo_frame: '_top' } do |f| %>
202
+ <div class="dialog-body">
203
+ <%= f.spree_text_field :name, required: true %>
204
+ <%= f.spree_text_area :description %>
205
+ </div>
206
+
207
+ <div class="dialog-footer">
208
+ <%= dialog_discard_button %>
209
+ <%= turbo_save_button_tag 'Create Item' %>
210
+ </div>
211
+ <% end %>
212
+ </div>
213
+ </div>
214
+ <% end %>
215
+ ```
216
+
217
+ ## Drawer
218
+
219
+ Drawers are slide-out panels typically used for filters, secondary forms, or detailed views without leaving the current page.
220
+
221
+ ### Basic Usage
222
+
223
+ ```erb
224
+ <div class="drawer" data-controller="drawer">
225
+ <%= drawer_header('Filter Options') %>
226
+
227
+ <div class="drawer-body">
228
+ <!-- Drawer content -->
229
+ </div>
230
+
231
+ <div class="drawer-footer">
232
+ <%= drawer_discard_button %>
233
+ <button type="submit" class="btn btn-primary">Apply Filters</button>
234
+ </div>
235
+ </div>
236
+ ```
237
+
238
+ ### `drawer_header`
239
+
240
+ Creates a drawer header with title and close button.
241
+
242
+ ```erb
243
+ <%= drawer_header('Filters') %>
244
+ <%= drawer_header('Details', 'custom-drawer') %>
245
+ ```
246
+
247
+ | Parameter | Type | Default | Description |
248
+ |-----------|------|---------|-------------|
249
+ | `title` | String | required | The drawer title |
250
+ | `controller_name` | String | `drawer` | Stimulus controller name for the close action |
251
+
252
+ **Renders:**
253
+
254
+ ```html
255
+ <div class="drawer-header">
256
+ <h5 class="drawer-title">Filters</h5>
257
+ <button type="button" class="btn-close" data-action="drawer#close" data-dismiss="drawer"></button>
258
+ </div>
259
+ ```
260
+
261
+ ### `drawer_close_button`
262
+
263
+ Creates a standalone close button for drawers.
264
+
265
+ ```erb
266
+ <%= drawer_close_button %>
267
+ <%= drawer_close_button('custom-drawer') %>
268
+ ```
269
+
270
+ | Parameter | Type | Default | Description |
271
+ |-----------|------|---------|-------------|
272
+ | `controller_name` | String | `drawer` | Stimulus controller name |
273
+
274
+ ### `drawer_discard_button`
275
+
276
+ Creates a "Discard" button that closes the drawer.
277
+
278
+ ```erb
279
+ <%= drawer_discard_button %>
280
+ ```
281
+
282
+ | Parameter | Type | Default | Description |
283
+ |-----------|------|---------|-------------|
284
+ | `controller_name` | String | `drawer` | Stimulus controller name |
285
+
286
+ ## Icon
287
+
288
+ Icons are rendered using the [Tabler Icons](https://tabler.io/icons) library.
289
+
290
+ ### Basic Usage
291
+
292
+ ```erb
293
+ <%= icon('package') %>
294
+ <%= icon('shopping-cart', class: 'text-primary') %>
295
+ <%= icon('check', class: 'text-success', height: 24) %>
296
+ ```
297
+
298
+ ### Options
299
+
300
+ | Option | Type | Default | Description |
301
+ |--------|------|---------|-------------|
302
+ | `class` | String | - | Additional CSS classes |
303
+ | `height` | Integer | - | Icon size in pixels |
304
+ | `style` | String | - | Additional inline styles |
305
+
306
+ ### Output
307
+
308
+ ```html
309
+ <i class="ti ti-package"></i>
310
+ <i class="ti ti-shopping-cart text-primary"></i>
311
+ <i class="ti ti-check text-success" style="font-size: 24px !important;"></i>
312
+ ```
313
+
314
+ ### Legacy Icon Names
315
+
316
+ For backwards compatibility, legacy icon names are automatically translated:
317
+
318
+ | Legacy Name | Tabler Icon |
319
+ |-------------|-------------|
320
+ | `save` | `device-floppy` |
321
+ | `edit` | `pencil` |
322
+ | `delete` | `trash` |
323
+ | `add` | `plus` |
324
+ | `cancel` | `x` |
325
+
326
+ ### Common Icons
327
+
328
+ | Icon | Name | Usage |
329
+ |------|------|-------|
330
+ | <i class="ti ti-pencil"></i> | `pencil` | Edit actions |
331
+ | <i class="ti ti-trash"></i> | `trash` | Delete actions |
332
+ | <i class="ti ti-plus"></i> | `plus` | Add/create actions |
333
+ | <i class="ti ti-eye"></i> | `eye` | View/preview |
334
+ | <i class="ti ti-download"></i> | `download` | Download/export |
335
+ | <i class="ti ti-upload"></i> | `upload` | Upload/import |
336
+ | <i class="ti ti-check"></i> | `check` | Success/confirm |
337
+ | <i class="ti ti-x"></i> | `x` | Close/cancel |
338
+ | <i class="ti ti-dots-vertical"></i> | `dots-vertical` | More options |
339
+ | <i class="ti ti-chevron-down"></i> | `chevron-down` | Expand |
340
+ | <i class="ti ti-chevron-right"></i> | `chevron-right` | Navigate |
341
+
342
+ ## Image
343
+
344
+ Displays optimized images with automatic WebP conversion and retina support.
345
+
346
+ ### Basic Usage
347
+
348
+ ```erb
349
+ <%= spree_image_tag(product.images.first, width: 100, height: 100) %>
350
+ <%= spree_image_tag(current_store.logo, width: 200, height: 60) %>
351
+ <%= spree_image_tag(taxon.image, width: 400, height: 300, class: 'rounded') %>
352
+ ```
353
+
354
+ ### Options
355
+
356
+ | Option | Type | Default | Description |
357
+ |--------|------|---------|-------------|
358
+ | `image` | Asset/Attachment | required | `Spree::Asset` or ActiveStorage attachment |
359
+ | `width` | Integer | - | Display width in pixels |
360
+ | `height` | Integer | - | Display height in pixels |
361
+ | `class` | String | - | CSS classes |
362
+ | `alt` | String | - | Alt text for accessibility |
363
+ | `loading` | Symbol | - | `:lazy` or `:eager` |
364
+
365
+ ### Features
366
+
367
+ - **Retina support** - Automatically scales dimensions by 2x for sharp display
368
+ - **WebP conversion** - Outputs optimized WebP format
369
+ - **Smart cropping** - When both dimensions provided, crops to fill
370
+ - **Aspect ratio preservation** - When one dimension provided, maintains ratio
371
+
372
+ ### Examples
373
+
374
+ ```erb
375
+ <%# Product thumbnail in index table %>
376
+ <% if product.has_images? %>
377
+ <%= spree_image_tag product.default_image, width: 48, height: 48, class: 'rounded' %>
378
+ <% else %>
379
+ <div class="bg-light rounded d-flex align-items-center justify-content-center" style="width: 48px; height: 48px;">
380
+ <%= icon('photo-off', class: 'text-muted') %>
381
+ </div>
382
+ <% end %>
383
+
384
+ <%# Store logo in header %>
385
+ <%= spree_image_tag current_store.logo, width: 120, height: 40, alt: current_store.name %>
386
+
387
+ <%# Category image %>
388
+ <%= spree_image_tag taxon.image, width: 300, height: 200, class: 'card-img-top' %>
389
+ ```
390
+
391
+ ### With Placeholder
392
+
393
+ ```erb
394
+ <% if @brand.logo.attached? %>
395
+ <%= spree_image_tag @brand.logo, width: 100, height: 100 %>
396
+ <% else %>
397
+ <div class="placeholder-image">
398
+ <%= icon('photo') %>
399
+ </div>
400
+ <% end %>
401
+ ```
402
+
403
+ > **INFO:** For comprehensive documentation on image handling, storage configuration, and best practices, see the [Media](/developer/core-concepts/media) guide.
404
+
405
+ ## Tooltip
406
+
407
+ Tooltips provide additional context on hover.
408
+
409
+ ### Basic Usage
410
+
411
+ ```erb
412
+ <span data-controller="tooltip">
413
+ <%= icon('info-circle') %>
414
+ <%= tooltip('This is helpful information') %>
415
+ </span>
416
+ ```
417
+
418
+ ### `tooltip`
419
+
420
+ Creates a tooltip container.
421
+
422
+ ```erb
423
+ <%= tooltip('Simple text tooltip') %>
424
+
425
+ <%= tooltip do %>
426
+ <strong>Rich content</strong> with <em>formatting</em>
427
+ <% end %>
428
+ ```
429
+
430
+ | Parameter | Type | Description |
431
+ |-----------|------|-------------|
432
+ | `text` | String | Tooltip text (or use block for rich content) |
433
+
434
+ ### `help_bubble`
435
+
436
+ Creates an info icon with a tooltip - commonly used for form field hints.
437
+
438
+ ```erb
439
+ <%= help_bubble('This field is used for SEO optimization') %>
440
+ <%= help_bubble('Shown below the field', 'bottom') %>
441
+ <%= help_bubble('Custom styled', 'top', css: 'text-primary') %>
442
+ ```
443
+
444
+ | Parameter | Type | Default | Description |
445
+ |-----------|------|---------|-------------|
446
+ | `text` | String | required | Tooltip text |
447
+ | `placement` | String | `top` | Tooltip position: `top`, `bottom`, `left`, `right` |
448
+ | `css` | String | `text-xs text-muted...` | CSS classes for the icon |
449
+
450
+ **Output:**
451
+
452
+ ```html
453
+ <span data-controller="tooltip" data-tooltip-placement-value="top">
454
+ <i class="ti ti-info-square-rounded text-xs text-muted cursor-default opacity-75"></i>
455
+ <span role="tooltip" data-tooltip-target="tooltip" class="tooltip-container">
456
+ This field is used for SEO optimization
457
+ </span>
458
+ </span>
459
+ ```
460
+
461
+ ## Active Badge
462
+
463
+ Displays a status badge indicating active/inactive state.
464
+
465
+ ### Basic Usage
466
+
467
+ ```erb
468
+ <%= active_badge(product.active?) %>
469
+ <%= active_badge(user.confirmed?) %>
470
+ <%= active_badge(order.paid?, label: 'Paid') %>
471
+ ```
472
+
473
+ ### Options
474
+
475
+ | Option | Type | Default | Description |
476
+ |--------|------|---------|-------------|
477
+ | `condition` | Boolean | required | The condition to evaluate |
478
+ | `label` | String | Yes/No | Custom label text |
479
+
480
+ ### Output
481
+
482
+ When condition is `true`:
483
+
484
+ ```html
485
+ <span class="badge badge-active">
486
+ <i class="ti ti-check"></i> Yes
487
+ </span>
488
+ ```
489
+
490
+ When condition is `false`:
491
+
492
+ ```html
493
+ <span class="badge badge-inactive">No</span>
494
+ ```
495
+
496
+ ### Custom Labels
497
+
498
+ ```erb
499
+ <%= active_badge(subscription.active?, label: subscription.active? ? 'Active' : 'Expired') %>
500
+ <%= active_badge(feature.enabled?, label: feature.enabled? ? 'Enabled' : 'Disabled') %>
501
+ ```
502
+
503
+ ## Avatar
504
+
505
+ Renders a user avatar with automatic fallback to initials.
506
+
507
+ ### Basic Usage
508
+
509
+ ```erb
510
+ <%= render_avatar(current_user) %>
511
+ <%= render_avatar(user, width: 48, height: 48) %>
512
+ <%= render_avatar(admin, class: 'avatar-lg') %>
513
+ ```
514
+
515
+ ### Options
516
+
517
+ | Option | Type | Default | Description |
518
+ |--------|------|---------|-------------|
519
+ | `user` | Object | required | User object (must respond to `avatar` and `name`) |
520
+ | `width` | Integer | 128 | Avatar width in pixels |
521
+ | `height` | Integer | 128 | Avatar height in pixels |
522
+ | `class` | String | `avatar` | CSS classes |
523
+
524
+ ### Behavior
525
+
526
+ 1. If user has an attached avatar image → displays the image
527
+ 2. Otherwise → displays user's initials on a colored background
528
+
529
+ ```erb
530
+ <!-- With avatar image -->
531
+ <img src="avatar.jpg" class="avatar" style="width: 128px; height: 128px;">
532
+
533
+ <!-- Without avatar (fallback) -->
534
+ <div class="avatar" style="width: 128px; height: 128px;">JD</div>
535
+ ```
536
+
537
+ ## Clipboard
538
+
539
+ Copy-to-clipboard functionality with visual feedback.
540
+
541
+ ### Basic Usage
542
+
543
+ ```erb
544
+ <%= clipboard_component(product.sku) %>
545
+ <%= clipboard_component(api_key) %>
546
+ ```
547
+
548
+ ### `clipboard_component`
549
+
550
+ Creates a complete clipboard component with hidden input and copy button.
551
+
552
+ ```erb
553
+ <%= clipboard_component('ABC-123-XYZ') %>
554
+ ```
555
+
556
+ | Parameter | Type | Description |
557
+ |-----------|------|-------------|
558
+ | `text` | String | The text to copy |
559
+
560
+ **Output:**
561
+
562
+ ```html
563
+ <span data-controller="clipboard" data-clipboard-success-content-value="<i class='ti ti-check mr-0 font-size-sm'></i>">
564
+ <input type="hidden" name="clipboard_source" value="ABC-123-XYZ" data-clipboard-target="source">
565
+ <button type="button" class="btn btn-clipboard" data-action="clipboard#copy" data-clipboard-target="button">
566
+ <i class="ti ti-copy mr-0 font-size-sm"></i>
567
+ <span role="tooltip" data-tooltip-target="tooltip" class="tooltip-container">Copy to clipboard</span>
568
+ </button>
569
+ </span>
570
+ ```
571
+
572
+ ### `clipboard_button`
573
+
574
+ Creates just the copy button (for custom layouts).
575
+
576
+ ```erb
577
+ <div data-controller="clipboard">
578
+ <input type="text" data-clipboard-target="source" value="custom-value">
579
+ <%= clipboard_button %>
580
+ </div>
581
+ ```
582
+
583
+ ### Inline with Text
584
+
585
+ ```erb
586
+ <div class="d-flex align-items-center gap-2">
587
+ <code><%= product.sku %></code>
588
+ <%= clipboard_component(product.sku) %>
589
+ </div>
590
+ ```
591
+
592
+ ## Progress Bar
593
+
594
+ Displays a progress bar with customizable range.
595
+
596
+ ### Basic Usage
597
+
598
+ ```erb
599
+ <%= progress_bar_component(75) %>
600
+ <%= progress_bar_component(150, max: 200) %>
601
+ <%= progress_bar_component(50, min: 0, max: 100) %>
602
+ ```
603
+
604
+ ### Options
605
+
606
+ | Option | Type | Default | Description |
607
+ |--------|------|---------|-------------|
608
+ | `value` | Integer | required | Current progress value |
609
+ | `min` | Integer | 0 | Minimum value |
610
+ | `max` | Integer | 100 | Maximum value |
611
+
612
+ ### Output
613
+
614
+ ```html
615
+ <div class="progress">
616
+ <div class="progress-bar"
617
+ role="progressbar"
618
+ style="width: 75%"
619
+ aria-valuenow="75"
620
+ aria-valuemin="0"
621
+ aria-valuemax="100">
622
+ </div>
623
+ </div>
624
+ ```
625
+
626
+ ### Examples
627
+
628
+ ```erb
629
+ <!-- Inventory level -->
630
+ <%= progress_bar_component(stock_item.count_on_hand, max: stock_item.backorderable_threshold || 100) %>
631
+
632
+ <!-- Order fulfillment -->
633
+ <%= progress_bar_component(order.shipments.shipped.count, max: order.shipments.count) %>
634
+
635
+ <!-- Upload progress -->
636
+ <%= progress_bar_component(uploaded_count, max: total_count) %>
637
+ ```
638
+
639
+ ## Date & Time
640
+
641
+ Helpers for displaying dates and times in the user's local timezone.
642
+
643
+ ### `spree_date`
644
+
645
+ Renders a date in the user's local format.
646
+
647
+ ```erb
648
+ <%= spree_date(order.created_at) %>
649
+ <%= spree_date(product.available_on) %>
650
+ ```
651
+
652
+ ### `spree_time`
653
+
654
+ Renders a date and time in the user's local format.
655
+
656
+ ```erb
657
+ <%= spree_time(order.completed_at) %>
658
+ <%= spree_time(shipment.shipped_at) %>
659
+ ```
660
+
661
+ ### `spree_time_ago`
662
+
663
+ Renders a relative time (e.g., "2 hours ago") with a tooltip showing the full timestamp.
664
+
665
+ ```erb
666
+ <%= spree_time_ago(order.completed_at) %>
667
+ <%= spree_time_ago(comment.created_at) %>
668
+ ```
669
+
670
+ **Output:**
671
+
672
+ ```html
673
+ <span data-controller="tooltip">
674
+ <time datetime="2024-01-15T10:30:00Z" data-local="time-ago">2 hours ago</time>
675
+ <span role="tooltip" data-tooltip-target="tooltip" class="tooltip-container">
676
+ January 15, 2024 10:30 AM
677
+ </span>
678
+ </span>
679
+ ```
680
+
681
+ ### `local_time`
682
+
683
+ The underlying helper from [local_time gem](https://github.com/basecamp/local_time) - displays time in user's browser timezone.
684
+
685
+ ```erb
686
+ <%= local_time(order.completed_at) %>
687
+ <%= local_time(event.starts_at, format: '%B %e, %Y at %l:%M %p') %>
688
+ ```
689
+
690
+ ### Comparison
691
+
692
+ | Helper | Output | Use Case |
693
+ |--------|--------|----------|
694
+ | `spree_date` | "Jan 15, 2024" | Date-only display |
695
+ | `spree_time` | "Jan 15, 2024 10:30 AM" | Full timestamp |
696
+ | `spree_time_ago` | "2 hours ago" | Relative time with tooltip |
697
+ | `local_time` | "January 15, 2024 10:30 AM" | Customizable format |
698
+
699
+ ## Best Practices
700
+
701
+ **Use semantic components** - Choose the right component for the interaction (Dialog for focused tasks, Drawer for contextual panels)
702
+
703
+ **Provide feedback** - Use tooltips and badges to give users context about their actions
704
+
705
+ **Keep dropdowns focused** - Limit dropdown menus to related actions, use dividers to group items
706
+
707
+ **Use appropriate icons** - Choose icons that clearly represent the action
708
+
709
+ **Handle loading states** - Use `turbo_save_button_tag` for forms to show loading feedback
710
+
711
+ **Consider accessibility** - Components include ARIA attributes and keyboard navigation