m9sh 0.2.1 → 0.2.2

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 (125) hide show
  1. checksums.yaml +4 -4
  2. data/.idea/hotcdn.iml +30 -0
  3. data/.mise.toml +2 -2
  4. data/app/assets/config/manifest.js +4 -0
  5. data/app/assets/images/icons/activity.svg +3 -0
  6. data/app/assets/images/icons/bell.svg +4 -0
  7. data/app/assets/images/icons/book.svg +4 -0
  8. data/app/assets/images/icons/chevron-down.svg +3 -0
  9. data/app/assets/images/icons/chevron-left.svg +3 -0
  10. data/app/assets/images/icons/chevron-right.svg +3 -0
  11. data/app/assets/images/icons/credit-card.svg +4 -0
  12. data/app/assets/images/icons/dollar-sign.svg +3 -0
  13. data/app/assets/images/icons/edit.svg +4 -0
  14. data/app/assets/images/icons/github.svg +3 -0
  15. data/app/assets/images/icons/home.svg +4 -0
  16. data/app/assets/images/icons/info.svg +5 -0
  17. data/app/assets/images/icons/layout.svg +6 -0
  18. data/app/assets/images/icons/logout.svg +5 -0
  19. data/app/assets/images/icons/menu.svg +5 -0
  20. data/app/assets/images/icons/moon.svg +3 -0
  21. data/app/assets/images/icons/paintbrush.svg +6 -0
  22. data/app/assets/images/icons/search.svg +4 -0
  23. data/app/assets/images/icons/settings.svg +4 -0
  24. data/app/assets/images/icons/sun.svg +11 -0
  25. data/app/assets/images/icons/user.svg +4 -0
  26. data/app/assets/images/icons/users.svg +5 -0
  27. data/app/assets/stylesheets/tailwind.css +1180 -0
  28. data/app/components/backdrop_component.rb +103 -0
  29. data/app/components/docs/code_block_component.rb +56 -0
  30. data/app/components/docs/component_api_component.rb +16 -0
  31. data/app/components/docs/component_examples_component.rb +16 -0
  32. data/app/components/docs/component_header_component.html.erb +8 -0
  33. data/app/components/docs/component_header_component.rb +14 -0
  34. data/app/components/docs/component_installation_component.html.erb +15 -0
  35. data/app/components/docs/component_installation_component.rb +13 -0
  36. data/app/components/docs/component_page_component.html.erb +9 -0
  37. data/app/components/docs/component_page_component.rb +19 -0
  38. data/app/components/docs/component_preview_component.rb +318 -0
  39. data/app/components/docs/component_usage_component.rb +18 -0
  40. data/app/components/docs/prop_table_component.rb +64 -0
  41. data/app/controllers/application_controller.rb +3 -0
  42. data/app/controllers/blocks_controller.rb +51 -0
  43. data/app/controllers/docs_controller.rb +162 -0
  44. data/app/controllers/showcase_controller.rb +42 -0
  45. data/app/helpers/blocks_helper.rb +343 -0
  46. data/app/helpers/docs_helper.rb +3807 -0
  47. data/app/helpers/m9sh/toast_helper.rb +46 -0
  48. data/app/helpers/m9sh_helper.rb +343 -0
  49. data/app/javascript/application.js +3 -0
  50. data/app/javascript/controllers/application.js +9 -0
  51. data/app/javascript/controllers/backdrop_controller.js +137 -0
  52. data/app/javascript/controllers/color_customizer_controller.js +569 -0
  53. data/app/javascript/controllers/color_theme_controller.js +120 -0
  54. data/app/javascript/controllers/docs/component_preview_controller.js +149 -0
  55. data/app/javascript/controllers/docs/copy_button_controller.js +20 -0
  56. data/app/javascript/controllers/index.js +6 -0
  57. data/app/javascript/controllers/theme_controller.js +23 -0
  58. data/app/views/blocks/_sidebar.html.erb +31 -0
  59. data/app/views/blocks/_toc.html.erb +29 -0
  60. data/app/views/blocks/examples/dashboard-01.html.erb +180 -0
  61. data/app/views/blocks/examples/dashboard-02.html.erb +190 -0
  62. data/app/views/blocks/examples/dashboard-03.html.erb +210 -0
  63. data/app/views/blocks/examples/settings-01.html.erb +220 -0
  64. data/app/views/blocks/examples/settings-02.html.erb +231 -0
  65. data/app/views/blocks/examples/settings-03.html.erb +340 -0
  66. data/app/views/blocks/index.html.erb +65 -0
  67. data/app/views/docs/_sidebar.html.erb +47 -0
  68. data/app/views/docs/_toc.html.erb +19 -0
  69. data/app/views/docs/about.html.erb +68 -0
  70. data/app/views/docs/components/accordion.html.erb +196 -0
  71. data/app/views/docs/components/alert.html.erb +272 -0
  72. data/app/views/docs/components/alert_dialog.html.erb +232 -0
  73. data/app/views/docs/components/avatar.html.erb +207 -0
  74. data/app/views/docs/components/badge.html.erb +145 -0
  75. data/app/views/docs/components/breadcrumb.html.erb +264 -0
  76. data/app/views/docs/components/button.html.erb +229 -0
  77. data/app/views/docs/components/card.html.erb +378 -0
  78. data/app/views/docs/components/checkbox.html.erb +212 -0
  79. data/app/views/docs/components/collapsible.html.erb +252 -0
  80. data/app/views/docs/components/dialog.html.erb +323 -0
  81. data/app/views/docs/components/dropdown_menu.html.erb +289 -0
  82. data/app/views/docs/components/hover_card.html.erb +220 -0
  83. data/app/views/docs/components/input.html.erb +254 -0
  84. data/app/views/docs/components/label.html.erb +128 -0
  85. data/app/views/docs/components/main.html.erb +352 -0
  86. data/app/views/docs/components/navbar.html.erb +394 -0
  87. data/app/views/docs/components/navigation_menu.html.erb +226 -0
  88. data/app/views/docs/components/popover.html.erb +267 -0
  89. data/app/views/docs/components/progress.html.erb +107 -0
  90. data/app/views/docs/components/radio_group.html.erb +209 -0
  91. data/app/views/docs/components/select.html.erb +260 -0
  92. data/app/views/docs/components/separator.html.erb +162 -0
  93. data/app/views/docs/components/sheet.html.erb +270 -0
  94. data/app/views/docs/components/sidebar.html.erb +597 -0
  95. data/app/views/docs/components/skeleton.html.erb +150 -0
  96. data/app/views/docs/components/slider.html.erb +218 -0
  97. data/app/views/docs/components/spinner.html.erb +132 -0
  98. data/app/views/docs/components/switch.html.erb +148 -0
  99. data/app/views/docs/components/table.html.erb +259 -0
  100. data/app/views/docs/components/tabs.html.erb +225 -0
  101. data/app/views/docs/components/textarea.html.erb +239 -0
  102. data/app/views/docs/components/theme_toggle.html.erb +135 -0
  103. data/app/views/docs/components/toast.html.erb +205 -0
  104. data/app/views/docs/components/toaster.html.erb +227 -0
  105. data/app/views/docs/components/toggle.html.erb +154 -0
  106. data/app/views/docs/components/tooltip.html.erb +216 -0
  107. data/app/views/docs/components/typography.html.erb +180 -0
  108. data/app/views/docs/index.html.erb +143 -0
  109. data/app/views/docs/installation.html.erb +155 -0
  110. data/app/views/docs/simple_test.html.erb +13 -0
  111. data/app/views/docs/test_accordion.html.erb +14 -0
  112. data/app/views/docs/usage.html.erb +272 -0
  113. data/app/views/layouts/application.html.erb +107 -0
  114. data/app/views/layouts/backdrop.html.erb +77 -0
  115. data/app/views/shared/_app_navbar.html.erb +240 -0
  116. data/app/views/shared/_navbar.html.erb +69 -0
  117. data/app/views/showcase/v2/_components_grid.html.erb +38 -0
  118. data/app/views/showcase/v2/_features.html.erb +59 -0
  119. data/app/views/showcase/v2/_forms.html.erb +195 -0
  120. data/app/views/showcase/v2/_hero.html.erb +55 -0
  121. data/app/views/showcase/v2/_metrics.html.erb +107 -0
  122. data/app/views/showcase/v2.html.erb +18 -0
  123. data/lib/m9sh/version.rb +1 -1
  124. data/m9sh.gemspec +1 -1
  125. metadata +120 -1
@@ -0,0 +1,264 @@
1
+ <%= render Docs::ComponentPageComponent.new(title: "Breadcrumb") do |page| %>
2
+ <% page.with_header(
3
+ name: "Breadcrumb",
4
+ description: "Displays the path to the current resource using a hierarchy of links."
5
+ ) %>
6
+
7
+ <% page.with_installation(component_name: "breadcrumb") %>
8
+
9
+ <% page.with_usage do %>
10
+ <%= render Docs::CodeBlockComponent.new(
11
+ code: breadcrumb_usage_code,
12
+ language: "erb"
13
+ ) %>
14
+ <% end %>
15
+
16
+ <% page.with_examples do %>
17
+ <!-- Default Example -->
18
+ <% default_breadcrumb_html = capture do %>
19
+ <%= render M9sh::BreadcrumbComponent.new do |breadcrumb| %>
20
+ <% breadcrumb.with_item do |item| %>
21
+ <% item.with_link do %>
22
+ <%= link_to "Home", "#", class: "hover:text-foreground transition-colors" %>
23
+ <% end %>
24
+ <% end %>
25
+
26
+ <% breadcrumb.with_item do |item| %>
27
+ <% item.with_link do %>
28
+ <%= link_to "Components", "#", class: "hover:text-foreground transition-colors" %>
29
+ <% end %>
30
+ <% end %>
31
+
32
+ <% breadcrumb.with_item(current: true) do |item| %>
33
+ <% item.with_page do %>
34
+ Breadcrumb
35
+ <% end %>
36
+ <% end %>
37
+ <% end %>
38
+ <% end %>
39
+
40
+ <%= render Docs::ComponentPreviewComponent.new(
41
+ title: "Default",
42
+ preview_content: default_breadcrumb_html,
43
+ code: breadcrumb_default_code,
44
+ ai_command: breadcrumb_default_code
45
+ ) %>
46
+
47
+ <!-- With Icons Example -->
48
+ <% with_icons_html = capture do %>
49
+ <%= render M9sh::BreadcrumbComponent.new do |breadcrumb| %>
50
+ <% breadcrumb.with_item do |item| %>
51
+ <% item.with_link do %>
52
+ <%= link_to "#", class: "flex items-center gap-1 hover:text-foreground transition-colors" do %>
53
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
54
+ <path d="m3 9 9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/>
55
+ <polyline points="9 22 9 12 15 12 15 22"/>
56
+ </svg>
57
+ Home
58
+ <% end %>
59
+ <% end %>
60
+ <% end %>
61
+
62
+ <% breadcrumb.with_item do |item| %>
63
+ <% item.with_link do %>
64
+ <%= link_to "Documents", "#", class: "hover:text-foreground transition-colors" %>
65
+ <% end %>
66
+ <% end %>
67
+
68
+ <% breadcrumb.with_item(current: true) do |item| %>
69
+ <% item.with_page do %>
70
+ README.md
71
+ <% end %>
72
+ <% end %>
73
+ <% end %>
74
+ <% end %>
75
+
76
+ <%= render Docs::ComponentPreviewComponent.new(
77
+ title: "With Icons",
78
+ preview_content: with_icons_html,
79
+ code: breadcrumb_with_icons_code,
80
+ ai_command: breadcrumb_with_icons_code
81
+ ) %>
82
+
83
+ <!-- With Dropdown Example -->
84
+ <% with_dropdown_html = capture do %>
85
+ <%= render M9sh::BreadcrumbComponent.new do |breadcrumb| %>
86
+ <% breadcrumb.with_item do |item| %>
87
+ <% item.with_link do %>
88
+ <%= link_to "Home", "#", class: "hover:text-foreground transition-colors" %>
89
+ <% end %>
90
+ <% end %>
91
+
92
+ <% breadcrumb.with_item do |item| %>
93
+ <div class="relative group">
94
+ <button type="button" class="flex items-center gap-1 hover:text-foreground transition-colors">
95
+ <span>...</span>
96
+ <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
97
+ <polyline points="6 9 12 15 18 9"/>
98
+ </svg>
99
+ </button>
100
+ </div>
101
+ <% end %>
102
+
103
+ <% breadcrumb.with_item do |item| %>
104
+ <% item.with_link do %>
105
+ <%= link_to "Components", "#", class: "hover:text-foreground transition-colors" %>
106
+ <% end %>
107
+ <% end %>
108
+
109
+ <% breadcrumb.with_item(current: true) do |item| %>
110
+ <% item.with_page do %>
111
+ Breadcrumb
112
+ <% end %>
113
+ <% end %>
114
+ <% end %>
115
+ <% end %>
116
+
117
+ <%= render Docs::ComponentPreviewComponent.new(
118
+ title: "With Collapsed Items (Dropdown)",
119
+ preview_content: with_dropdown_html,
120
+ code: breadcrumb_dropdown_code,
121
+ ai_command: breadcrumb_dropdown_code
122
+ ) %>
123
+
124
+ <!-- Multiple Breadcrumbs Example -->
125
+ <% multiple_breadcrumb_html = capture do %>
126
+ <div class="space-y-4">
127
+ <%= render M9sh::BreadcrumbComponent.new do |breadcrumb| %>
128
+ <% breadcrumb.with_item do |item| %>
129
+ <% item.with_link do %>
130
+ <%= link_to "Home", "#", class: "hover:text-foreground transition-colors" %>
131
+ <% end %>
132
+ <% end %>
133
+
134
+ <% breadcrumb.with_item do |item| %>
135
+ <% item.with_link do %>
136
+ <%= link_to "Library", "#", class: "hover:text-foreground transition-colors" %>
137
+ <% end %>
138
+ <% end %>
139
+
140
+ <% breadcrumb.with_item(current: true) do |item| %>
141
+ <% item.with_page do %>
142
+ Data
143
+ <% end %>
144
+ <% end %>
145
+ <% end %>
146
+
147
+ <%= render M9sh::BreadcrumbComponent.new do |breadcrumb| %>
148
+ <% breadcrumb.with_item do |item| %>
149
+ <% item.with_link do %>
150
+ <%= link_to "App", "#", class: "hover:text-foreground transition-colors" %>
151
+ <% end %>
152
+ <% end %>
153
+
154
+ <% breadcrumb.with_item do |item| %>
155
+ <% item.with_link do %>
156
+ <%= link_to "Products", "#", class: "hover:text-foreground transition-colors" %>
157
+ <% end %>
158
+ <% end %>
159
+
160
+ <% breadcrumb.with_item(current: true) do |item| %>
161
+ <% item.with_page do %>
162
+ Product Details
163
+ <% end %>
164
+ <% end %>
165
+ <% end %>
166
+ </div>
167
+ <% end %>
168
+
169
+ <%= render Docs::ComponentPreviewComponent.new(
170
+ title: "Multiple Breadcrumbs",
171
+ preview_content: multiple_breadcrumb_html,
172
+ code: nil,
173
+ ai_command: nil
174
+ ) %>
175
+
176
+ <!-- Responsive Example -->
177
+ <% responsive_breadcrumb_html = capture do %>
178
+ <div class="w-full">
179
+ <%= render M9sh::BreadcrumbComponent.new do |breadcrumb| %>
180
+ <% breadcrumb.with_item do |item| %>
181
+ <% item.with_link do %>
182
+ <%= link_to "Dashboard", "#", class: "hover:text-foreground transition-colors" %>
183
+ <% end %>
184
+ <% end %>
185
+
186
+ <% breadcrumb.with_item do |item| %>
187
+ <% item.with_link do %>
188
+ <%= link_to "Projects", "#", class: "hover:text-foreground transition-colors" %>
189
+ <% end %>
190
+ <% end %>
191
+
192
+ <% breadcrumb.with_item do |item| %>
193
+ <% item.with_link do %>
194
+ <%= link_to "Web Development", "#", class: "hover:text-foreground transition-colors" %>
195
+ <% end %>
196
+ <% end %>
197
+
198
+ <% breadcrumb.with_item do |item| %>
199
+ <% item.with_link do %>
200
+ <%= link_to "E-Commerce", "#", class: "hover:text-foreground transition-colors" %>
201
+ <% end %>
202
+ <% end %>
203
+
204
+ <% breadcrumb.with_item(current: true) do |item| %>
205
+ <% item.with_page do %>
206
+ Shopping Cart Implementation
207
+ <% end %>
208
+ <% end %>
209
+ <% end %>
210
+ </div>
211
+ <% end %>
212
+
213
+ <%= render Docs::ComponentPreviewComponent.new(
214
+ title: "Responsive (Long Path)",
215
+ preview_content: responsive_breadcrumb_html,
216
+ code: nil,
217
+ ai_command: nil
218
+ ) %>
219
+ <% end %>
220
+
221
+ <% page.with_api do %>
222
+ <h3 class="text-lg font-semibold">Breadcrumb Component</h3>
223
+ <%= render Docs::PropTableComponent.new(
224
+ props: [
225
+ {
226
+ name: "class_name",
227
+ type: "String",
228
+ default: "nil",
229
+ description: "Additional CSS classes to add to the nav element"
230
+ }
231
+ ]
232
+ ) %>
233
+
234
+ <h3 class="text-lg font-semibold mt-6">Item Component</h3>
235
+ <%= render Docs::PropTableComponent.new(
236
+ props: [
237
+ {
238
+ name: "current",
239
+ type: "Boolean",
240
+ default: "false",
241
+ description: "Whether this item represents the current page"
242
+ }
243
+ ]
244
+ ) %>
245
+
246
+ <h3 class="text-lg font-semibold mt-6">Item Slots</h3>
247
+ <%= render Docs::PropTableComponent.new(
248
+ props: [
249
+ {
250
+ name: "link",
251
+ type: "Slot",
252
+ default: nil,
253
+ description: "Content for a navigable breadcrumb item (usually a link_to)"
254
+ },
255
+ {
256
+ name: "page",
257
+ type: "Slot",
258
+ default: nil,
259
+ description: "Content for the current page (non-navigable)"
260
+ }
261
+ ]
262
+ ) %>
263
+ <% end %>
264
+ <% end %>
@@ -0,0 +1,229 @@
1
+ <%= render Docs::ComponentPageComponent.new(title: "Button") do |page| %>
2
+ <% page.with_header(
3
+ name: "Button",
4
+ description: "Displays a button or a component that looks like a button."
5
+ ) %>
6
+
7
+ <% page.with_installation(component_name: "button") %>
8
+
9
+ <% page.with_usage do %>
10
+ <%= render Docs::CodeBlockComponent.new(
11
+ code: button_usage_code,
12
+ language: "erb"
13
+ ) %>
14
+ <% end %>
15
+
16
+ <% page.with_examples do %>
17
+ <!-- Default Example -->
18
+ <% button = M9sh::ButtonComponent.new %>
19
+ <% button_html = capture do %>
20
+ <%= render button do %>
21
+ Button
22
+ <% end %>
23
+ <% end %>
24
+
25
+ <%= render Docs::ComponentPreviewComponent.new(
26
+ title: "Default",
27
+ preview_content: button_html,
28
+ code: button_default_code,
29
+ ai_command: button_default_code
30
+ ) %>
31
+
32
+ <!-- Variants Example -->
33
+ <% variants_html = capture do %>
34
+ <div class="flex flex-wrap gap-2">
35
+ <%= render M9sh::ButtonComponent.new(variant: :default) do %>
36
+ Default
37
+ <% end %>
38
+ <%= render M9sh::ButtonComponent.new(variant: :secondary) do %>
39
+ Secondary
40
+ <% end %>
41
+ <%= render M9sh::ButtonComponent.new(variant: :destructive) do %>
42
+ Destructive
43
+ <% end %>
44
+ <%= render M9sh::ButtonComponent.new(variant: :outline) do %>
45
+ Outline
46
+ <% end %>
47
+ <%= render M9sh::ButtonComponent.new(variant: :ghost) do %>
48
+ Ghost
49
+ <% end %>
50
+ <%= render M9sh::ButtonComponent.new(variant: :link) do %>
51
+ Link
52
+ <% end %>
53
+ </div>
54
+ <% end %>
55
+
56
+ <%= render Docs::ComponentPreviewComponent.new(
57
+ title: "Variants",
58
+ preview_content: variants_html,
59
+ code: button_variants_code,
60
+ ai_command: button_variants_code
61
+ ) %>
62
+
63
+ <!-- Sizes Example -->
64
+ <% sizes_html = capture do %>
65
+ <div class="flex items-center gap-2">
66
+ <%= render M9sh::ButtonComponent.new(size: :sm) do %>
67
+ Small
68
+ <% end %>
69
+ <%= render M9sh::ButtonComponent.new(size: :md) do %>
70
+ Medium
71
+ <% end %>
72
+ <%= render M9sh::ButtonComponent.new(size: :lg) do %>
73
+ Large
74
+ <% end %>
75
+ </div>
76
+ <% end %>
77
+
78
+ <%= render Docs::ComponentPreviewComponent.new(
79
+ title: "Sizes",
80
+ preview_content: sizes_html,
81
+ code: button_sizes_code,
82
+ ai_command: button_sizes_code
83
+ ) %>
84
+
85
+ <!-- Disabled Example -->
86
+ <% disabled_html = capture do %>
87
+ <div class="flex gap-2">
88
+ <%= render M9sh::ButtonComponent.new(disabled: true) do %>
89
+ Disabled Default
90
+ <% end %>
91
+ <%= render M9sh::ButtonComponent.new(variant: :secondary, disabled: true) do %>
92
+ Disabled Secondary
93
+ <% end %>
94
+ <%= render M9sh::ButtonComponent.new(variant: :outline, disabled: true) do %>
95
+ Disabled Outline
96
+ <% end %>
97
+ </div>
98
+ <% end %>
99
+
100
+ <%= render Docs::ComponentPreviewComponent.new(
101
+ title: "Disabled",
102
+ preview_content: disabled_html,
103
+ code: button_disabled_code,
104
+ ai_command: button_disabled_code
105
+ ) %>
106
+
107
+ <!-- Icon Button Example -->
108
+ <% icon_html = capture do %>
109
+ <div class="flex gap-2">
110
+ <%= render M9sh::ButtonComponent.new(variant: :outline, size: :icon) do %>
111
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
112
+ <path d="M6 9l6 6 6-6"/>
113
+ </svg>
114
+ <% end %>
115
+ <%= render M9sh::ButtonComponent.new(variant: :ghost, size: :icon) do %>
116
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
117
+ <path d="M12 5v14M5 12h14"/>
118
+ </svg>
119
+ <% end %>
120
+ <%= render M9sh::ButtonComponent.new(size: :icon) do %>
121
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
122
+ <rect width="18" height="18" x="3" y="3" rx="2" ry="2"/>
123
+ </svg>
124
+ <% end %>
125
+ <%= render M9sh::ButtonComponent.new(variant: :destructive, size: :icon) do %>
126
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
127
+ <path d="M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"/>
128
+ </svg>
129
+ <% end %>
130
+ </div>
131
+ <% end %>
132
+
133
+ <%= render Docs::ComponentPreviewComponent.new(
134
+ title: "Icon Buttons",
135
+ preview_content: icon_html,
136
+ code: button_icon_code,
137
+ ai_command: button_icon_code
138
+ ) %>
139
+
140
+ <!-- With Icons Example -->
141
+ <% with_icons_html = capture do %>
142
+ <div class="flex gap-2">
143
+ <%= render M9sh::ButtonComponent.new do %>
144
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2">
145
+ <path d="M19 12H5M12 19l-7-7 7-7"/>
146
+ </svg>
147
+ Back
148
+ <% end %>
149
+ <%= render M9sh::ButtonComponent.new(variant: :secondary) do %>
150
+ Next
151
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="ml-2">
152
+ <path d="M5 12h14M12 5l7 7-7 7"/>
153
+ </svg>
154
+ <% end %>
155
+ <%= render M9sh::ButtonComponent.new(variant: :outline) do %>
156
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="mr-2">
157
+ <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/>
158
+ </svg>
159
+ Download
160
+ <% end %>
161
+ </div>
162
+ <% end %>
163
+
164
+ <%= render Docs::ComponentPreviewComponent.new(
165
+ title: "With Icons",
166
+ preview_content: with_icons_html,
167
+ code: nil,
168
+ ai_command: nil
169
+ ) %>
170
+
171
+ <!-- Loading State Example -->
172
+ <% loading_html = capture do %>
173
+ <div class="flex gap-2">
174
+ <%= render M9sh::ButtonComponent.new(disabled: true) do %>
175
+ <svg class="mr-2 h-4 w-4 animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
176
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
177
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
178
+ </svg>
179
+ Loading...
180
+ <% end %>
181
+ <%= render M9sh::ButtonComponent.new(variant: :outline, disabled: true) do %>
182
+ <svg class="mr-2 h-4 w-4 animate-spin" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
183
+ <circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
184
+ <path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
185
+ </svg>
186
+ Please wait
187
+ <% end %>
188
+ </div>
189
+ <% end %>
190
+
191
+ <%= render Docs::ComponentPreviewComponent.new(
192
+ title: "Loading State",
193
+ preview_content: loading_html,
194
+ code: nil,
195
+ ai_command: nil
196
+ ) %>
197
+ <% end %>
198
+
199
+ <% page.with_api do %>
200
+ <%= render Docs::PropTableComponent.new(
201
+ props: [
202
+ {
203
+ name: "variant",
204
+ type: "Symbol",
205
+ default: ":default",
206
+ description: "The visual style variant. Options: :default, :secondary, :destructive, :outline, :ghost, :link"
207
+ },
208
+ {
209
+ name: "size",
210
+ type: "Symbol",
211
+ default: ":md",
212
+ description: "The size of the button. Options: :sm, :md, :lg, :icon"
213
+ },
214
+ {
215
+ name: "type",
216
+ type: "String",
217
+ default: '"button"',
218
+ description: "The HTML button type attribute. Options: 'button', 'submit', 'reset'"
219
+ },
220
+ {
221
+ name: "disabled",
222
+ type: "Boolean",
223
+ default: "false",
224
+ description: "Whether the button is disabled"
225
+ }
226
+ ]
227
+ ) %>
228
+ <% end %>
229
+ <% end %>