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,378 @@
1
+ <%= render Docs::ComponentPageComponent.new(title: "Card") do |page| %>
2
+ <% page.with_header(
3
+ name: "Card",
4
+ description: "Displays a flexible container component with optional header, body, and footer sections for organizing content."
5
+ ) %>
6
+
7
+ <% page.with_installation(component_name: "card") %>
8
+
9
+ <% page.with_usage do %>
10
+ <%= render Docs::CodeBlockComponent.new(
11
+ code: card_usage_code,
12
+ language: "erb"
13
+ ) %>
14
+ <% end %>
15
+
16
+ <% page.with_examples do %>
17
+ <!-- Default Card Example -->
18
+ <% default_card_html = capture do %>
19
+ <%= render M9sh::CardComponent.new do |card| %>
20
+ <% card.with_body do %>
21
+ <p class="text-sm">
22
+ This is a simple card with just body content. Cards provide a clean container with subtle borders and shadows.
23
+ </p>
24
+ <% end %>
25
+ <% end %>
26
+ <% end %>
27
+
28
+ <%= render Docs::ComponentPreviewComponent.new(
29
+ title: "Default",
30
+ preview_content: default_card_html,
31
+ code: card_usage_code,
32
+ ai_command: card_usage_code
33
+ ) %>
34
+
35
+ <!-- Card with Header -->
36
+ <% card_with_header_html = capture do %>
37
+ <%= render M9sh::CardComponent.new do |card| %>
38
+ <% card.with_header do |header| %>
39
+ <% header.with_title do %>
40
+ Card Title
41
+ <% end %>
42
+ <% header.with_description do %>
43
+ Card description provides additional context
44
+ <% end %>
45
+ <% end %>
46
+ <% card.with_body do %>
47
+ <p class="text-sm">
48
+ This card includes a header with a title and description. The header is automatically styled with appropriate spacing and typography.
49
+ </p>
50
+ <% end %>
51
+ <% end %>
52
+ <% end %>
53
+
54
+ <%= render Docs::ComponentPreviewComponent.new(
55
+ title: "With Header",
56
+ preview_content: card_with_header_html,
57
+ code: card_with_header_code,
58
+ ai_command: card_with_header_code
59
+ ) %>
60
+
61
+ <!-- Card with Footer -->
62
+ <% card_with_footer_html = capture do %>
63
+ <%= render M9sh::CardComponent.new do |card| %>
64
+ <% card.with_body do %>
65
+ <p class="text-sm">
66
+ This card includes a footer section below the main content, perfect for action buttons or metadata.
67
+ </p>
68
+ <% end %>
69
+ <% card.with_footer do %>
70
+ <p class="text-sm text-muted-foreground">Last updated: 2 hours ago</p>
71
+ <% end %>
72
+ <% end %>
73
+ <% end %>
74
+
75
+ <%= render Docs::ComponentPreviewComponent.new(
76
+ title: "With Footer",
77
+ preview_content: card_with_footer_html,
78
+ code: card_with_footer_code,
79
+ ai_command: card_with_footer_code
80
+ ) %>
81
+
82
+ <!-- Complete Card Example -->
83
+ <% complete_card_html = capture do %>
84
+ <%= render M9sh::CardComponent.new do |card| %>
85
+ <% card.with_header do |header| %>
86
+ <% header.with_title do %>
87
+ Create Project
88
+ <% end %>
89
+ <% header.with_description do %>
90
+ Deploy your new project in one-click.
91
+ <% end %>
92
+ <% end %>
93
+ <% card.with_body do %>
94
+ <div class="space-y-4">
95
+ <div class="space-y-2">
96
+ <%= render M9sh::LabelComponent.new(for_id: "project-name") do %>
97
+ Name
98
+ <% end %>
99
+ <%= render M9sh::InputComponent.new(
100
+ id: "project-name",
101
+ type: "text",
102
+ placeholder: "Name of your project"
103
+ ) %>
104
+ </div>
105
+ <div class="space-y-2">
106
+ <%= render M9sh::LabelComponent.new(for_id: "framework") do %>
107
+ Framework
108
+ <% end %>
109
+ <%= render M9sh::SelectComponent.new(
110
+ name: "framework",
111
+ options: ["Next.js", "SvelteKit", "Astro", "Nuxt.js"]
112
+ ) %>
113
+ </div>
114
+ </div>
115
+ <% end %>
116
+ <% card.with_footer do %>
117
+ <div class="flex justify-between w-full">
118
+ <%= render M9sh::ButtonComponent.new(variant: :outline) do %>
119
+ Cancel
120
+ <% end %>
121
+ <%= render M9sh::ButtonComponent.new do %>
122
+ Deploy
123
+ <% end %>
124
+ </div>
125
+ <% end %>
126
+ <% end %>
127
+ <% end %>
128
+
129
+ <%= render Docs::ComponentPreviewComponent.new(
130
+ title: "Complete Card",
131
+ preview_content: complete_card_html,
132
+ code: card_complete_code,
133
+ ai_command: card_complete_code
134
+ ) %>
135
+
136
+ <!-- Card with Header Action -->
137
+ <% card_with_action_html = capture do %>
138
+ <%= render M9sh::CardComponent.new(class: "max-w-md") do |card| %>
139
+ <% card.with_header do |header| %>
140
+ <% header.with_title do %>
141
+ Notifications
142
+ <% end %>
143
+ <% header.with_description do %>
144
+ You have 3 unread messages.
145
+ <% end %>
146
+ <% header.with_action do %>
147
+ <%= render M9sh::ButtonComponent.new(variant: :ghost, size: :sm) do %>
148
+ Mark all as read
149
+ <% end %>
150
+ <% end %>
151
+ <% end %>
152
+ <% card.with_body do %>
153
+ <div class="space-y-3">
154
+ <div class="flex items-start gap-3 p-3 rounded-md hover:bg-muted transition-colors border border-transparent hover:border-border">
155
+ <div class="flex-shrink-0 w-2 h-2 rounded-full bg-primary mt-2"></div>
156
+ <div class="flex-1 space-y-1">
157
+ <p class="text-sm font-medium">Your call has been confirmed.</p>
158
+ <p class="text-xs text-muted-foreground">5 minutes ago</p>
159
+ </div>
160
+ </div>
161
+ <div class="flex items-start gap-3 p-3 rounded-md hover:bg-muted transition-colors border border-transparent hover:border-border">
162
+ <div class="flex-shrink-0 w-2 h-2 rounded-full bg-primary mt-2"></div>
163
+ <div class="flex-1 space-y-1">
164
+ <p class="text-sm font-medium">You have a new message!</p>
165
+ <p class="text-xs text-muted-foreground">10 minutes ago</p>
166
+ </div>
167
+ </div>
168
+ <div class="flex items-start gap-3 p-3 rounded-md hover:bg-muted transition-colors border border-transparent hover:border-border">
169
+ <div class="flex-shrink-0 w-2 h-2 rounded-full bg-primary mt-2"></div>
170
+ <div class="flex-1 space-y-1">
171
+ <p class="text-sm font-medium">Your subscription is expiring soon!</p>
172
+ <p class="text-xs text-muted-foreground">2 hours ago</p>
173
+ </div>
174
+ </div>
175
+ </div>
176
+ <% end %>
177
+ <% end %>
178
+ <% end %>
179
+
180
+ <%= render Docs::ComponentPreviewComponent.new(
181
+ title: "With Header Action",
182
+ preview_content: card_with_action_html,
183
+ code: card_with_action_code,
184
+ ai_command: card_with_action_code
185
+ ) %>
186
+
187
+ <!-- Multiple Cards in a Grid -->
188
+ <% multiple_cards_html = capture do %>
189
+ <div class="grid gap-4 md:grid-cols-2 lg:grid-cols-3">
190
+ <%= render M9sh::CardComponent.new do |card| %>
191
+ <% card.with_header do |header| %>
192
+ <% header.with_title do %>
193
+ Total Revenue
194
+ <% end %>
195
+ <% header.with_description do %>
196
+ Monthly earnings
197
+ <% end %>
198
+ <% end %>
199
+ <% card.with_body do %>
200
+ <div class="text-2xl font-bold">$45,231.89</div>
201
+ <p class="text-xs text-muted-foreground mt-1">+20.1% from last month</p>
202
+ <% end %>
203
+ <% end %>
204
+
205
+ <%= render M9sh::CardComponent.new do |card| %>
206
+ <% card.with_header do |header| %>
207
+ <% header.with_title do %>
208
+ Subscriptions
209
+ <% end %>
210
+ <% header.with_description do %>
211
+ Active subscribers
212
+ <% end %>
213
+ <% end %>
214
+ <% card.with_body do %>
215
+ <div class="text-2xl font-bold">+2,350</div>
216
+ <p class="text-xs text-muted-foreground mt-1">+180.1% from last month</p>
217
+ <% end %>
218
+ <% end %>
219
+
220
+ <%= render M9sh::CardComponent.new do |card| %>
221
+ <% card.with_header do |header| %>
222
+ <% header.with_title do %>
223
+ Active Now
224
+ <% end %>
225
+ <% header.with_description do %>
226
+ Current online users
227
+ <% end %>
228
+ <% end %>
229
+ <% card.with_body do %>
230
+ <div class="text-2xl font-bold">+573</div>
231
+ <p class="text-xs text-muted-foreground mt-1">+201 since last hour</p>
232
+ <% end %>
233
+ <% end %>
234
+ </div>
235
+ <% end %>
236
+
237
+ <%= render Docs::ComponentPreviewComponent.new(
238
+ title: "Multiple Cards",
239
+ preview_content: multiple_cards_html,
240
+ code: nil,
241
+ ai_command: nil
242
+ ) %>
243
+
244
+ <!-- Card with Custom Content -->
245
+ <% custom_content_card_html = capture do %>
246
+ <%= render M9sh::CardComponent.new(class: "max-w-md") do |card| %>
247
+ <% card.with_header do |header| %>
248
+ <% header.with_title do %>
249
+ Team Members
250
+ <% end %>
251
+ <% header.with_description do %>
252
+ Invite your team members to collaborate.
253
+ <% end %>
254
+ <% end %>
255
+ <% card.with_body do %>
256
+ <div class="space-y-4">
257
+ <div class="flex items-center justify-between p-2 rounded-md hover:bg-muted transition-colors">
258
+ <div class="flex items-center gap-3">
259
+ <%= render M9sh::AvatarComponent.new(fallback: "JD", class: "h-10 w-10") %>
260
+ <div>
261
+ <p class="text-sm font-medium">John Doe</p>
262
+ <p class="text-xs text-muted-foreground">john@example.com</p>
263
+ </div>
264
+ </div>
265
+ <%= render M9sh::BadgeComponent.new(variant: :secondary) do %>
266
+ Owner
267
+ <% end %>
268
+ </div>
269
+ <div class="flex items-center justify-between p-2 rounded-md hover:bg-muted transition-colors">
270
+ <div class="flex items-center gap-3">
271
+ <%= render M9sh::AvatarComponent.new(fallback: "JS", class: "h-10 w-10") %>
272
+ <div>
273
+ <p class="text-sm font-medium">Jane Smith</p>
274
+ <p class="text-xs text-muted-foreground">jane@example.com</p>
275
+ </div>
276
+ </div>
277
+ <%= render M9sh::BadgeComponent.new(variant: :secondary) do %>
278
+ Admin
279
+ <% end %>
280
+ </div>
281
+ <div class="flex items-center justify-between p-2 rounded-md hover:bg-muted transition-colors">
282
+ <div class="flex items-center gap-3">
283
+ <%= render M9sh::AvatarComponent.new(fallback: "BJ", class: "h-10 w-10") %>
284
+ <div>
285
+ <p class="text-sm font-medium">Bob Johnson</p>
286
+ <p class="text-xs text-muted-foreground">bob@example.com</p>
287
+ </div>
288
+ </div>
289
+ <%= render M9sh::BadgeComponent.new(variant: :secondary) do %>
290
+ Member
291
+ <% end %>
292
+ </div>
293
+ </div>
294
+ <% end %>
295
+ <% card.with_footer do %>
296
+ <%= render M9sh::ButtonComponent.new(class: "w-full") do %>
297
+ Invite Team Member
298
+ <% end %>
299
+ <% end %>
300
+ <% end %>
301
+ <% end %>
302
+
303
+ <%= render Docs::ComponentPreviewComponent.new(
304
+ title: "Custom Content",
305
+ preview_content: custom_content_card_html,
306
+ code: nil,
307
+ ai_command: nil
308
+ ) %>
309
+ <% end %>
310
+
311
+ <% page.with_api do %>
312
+ <h3 class="text-lg font-semibold">Card Component</h3>
313
+ <p class="text-sm text-muted-foreground mb-4">
314
+ The Card component accepts all standard HTML attributes which are passed through to the root div element.
315
+ </p>
316
+
317
+ <h3 class="text-lg font-semibold mt-6">Card Slots</h3>
318
+ <%= render Docs::PropTableComponent.new(
319
+ props: [
320
+ {
321
+ name: "header",
322
+ type: "HeaderComponent",
323
+ default: nil,
324
+ description: "Optional header section. Supports title, description, and action slots"
325
+ },
326
+ {
327
+ name: "body",
328
+ type: "Slot",
329
+ default: nil,
330
+ description: "Main content area of the card"
331
+ },
332
+ {
333
+ name: "footer",
334
+ type: "Slot",
335
+ default: nil,
336
+ description: "Optional footer section for actions or metadata"
337
+ }
338
+ ]
339
+ ) %>
340
+
341
+ <h3 class="text-lg font-semibold mt-6">Header Component Slots</h3>
342
+ <%= render Docs::PropTableComponent.new(
343
+ props: [
344
+ {
345
+ name: "title",
346
+ type: "Slot",
347
+ default: nil,
348
+ description: "The title/heading text displayed in the header"
349
+ },
350
+ {
351
+ name: "description",
352
+ type: "Slot",
353
+ default: nil,
354
+ description: "Optional description text displayed below the title"
355
+ },
356
+ {
357
+ name: "action",
358
+ type: "Slot",
359
+ default: nil,
360
+ description: "Optional action element (e.g., button, link) displayed in the top-right corner of the header"
361
+ }
362
+ ]
363
+ ) %>
364
+
365
+ <div class="mt-6 space-y-2">
366
+ <h3 class="text-lg font-semibold">Notes</h3>
367
+ <ul class="list-disc list-inside text-sm text-muted-foreground space-y-1">
368
+ <li>All slots (header, body, footer) are optional and can be used in any combination</li>
369
+ <li>The card includes hover effects that enhance the border and shadow on mouse over</li>
370
+ <li>The header component supports a grid layout when an action slot is provided</li>
371
+ <li>The header title and description are automatically styled with appropriate typography</li>
372
+ <li>The body content is wrapped in a container with horizontal padding for consistent spacing</li>
373
+ <li>The footer automatically aligns items with proper spacing</li>
374
+ <li>Cards are responsive and work well in grid layouts (as shown in the Multiple Cards example)</li>
375
+ </ul>
376
+ </div>
377
+ <% end %>
378
+ <% end %>
@@ -0,0 +1,212 @@
1
+ <%= render Docs::ComponentPageComponent.new(title: "Checkbox") do |page| %>
2
+ <% page.with_header(name: "Checkbox", description: "A control that allows the user to toggle between checked and not checked.") %>
3
+ <% page.with_installation(component_name: "checkbox") %>
4
+ <% page.with_usage do %>
5
+ <%= render Docs::CodeBlockComponent.new(code: checkbox_usage_code, language: "erb") %>
6
+ <% end %>
7
+ <% page.with_examples do %>
8
+ <!-- Default Example -->
9
+ <% default_html = capture do %>
10
+ <%= render M9sh::CheckboxComponent.new(name: "default") %>
11
+ <% end %>
12
+
13
+ <%= render Docs::ComponentPreviewComponent.new(
14
+ title: "Default",
15
+ preview_content: default_html,
16
+ code: checkbox_usage_code,
17
+ ai_command: checkbox_usage_code
18
+ ) %>
19
+
20
+ <!-- With Label Example -->
21
+ <% with_label_html = capture do %>
22
+ <div class="flex items-center space-x-2">
23
+ <%= render M9sh::CheckboxComponent.new(name: "terms", id: "terms") %>
24
+ <%= render M9sh::LabelComponent.new(for_id: "terms") do %>
25
+ Accept terms and conditions
26
+ <% end %>
27
+ </div>
28
+ <% end %>
29
+
30
+ <%= render Docs::ComponentPreviewComponent.new(
31
+ title: "With Label",
32
+ preview_content: with_label_html,
33
+ code: checkbox_with_label_code,
34
+ ai_command: checkbox_with_label_code
35
+ ) %>
36
+
37
+ <!-- Checked State Example -->
38
+ <% checked_html = capture do %>
39
+ <div class="flex items-center space-x-2">
40
+ <%= render M9sh::CheckboxComponent.new(name: "checked", id: "checked", checked: true) %>
41
+ <%= render M9sh::LabelComponent.new(for_id: "checked") do %>
42
+ This checkbox is checked by default
43
+ <% end %>
44
+ </div>
45
+ <% end %>
46
+
47
+ <%= render Docs::ComponentPreviewComponent.new(
48
+ title: "Checked State",
49
+ preview_content: checked_html,
50
+ code: checkbox_checked_code,
51
+ ai_command: checkbox_checked_code
52
+ ) %>
53
+
54
+ <!-- Disabled State Example -->
55
+ <% disabled_html = capture do %>
56
+ <div class="flex flex-col space-y-4">
57
+ <div class="flex items-center space-x-2">
58
+ <%= render M9sh::CheckboxComponent.new(name: "disabled", id: "disabled", disabled: true) %>
59
+ <%= render M9sh::LabelComponent.new(for_id: "disabled") do %>
60
+ Disabled unchecked
61
+ <% end %>
62
+ </div>
63
+ <div class="flex items-center space-x-2">
64
+ <%= render M9sh::CheckboxComponent.new(name: "disabled_checked", id: "disabled_checked", checked: true, disabled: true) %>
65
+ <%= render M9sh::LabelComponent.new(for_id: "disabled_checked") do %>
66
+ Disabled checked
67
+ <% end %>
68
+ </div>
69
+ </div>
70
+ <% end %>
71
+
72
+ <%= render Docs::ComponentPreviewComponent.new(
73
+ title: "Disabled State",
74
+ preview_content: disabled_html,
75
+ code: checkbox_disabled_code,
76
+ ai_command: checkbox_disabled_code
77
+ ) %>
78
+
79
+ <!-- Multiple Checkboxes Example -->
80
+ <% multiple_html = capture do %>
81
+ <div class="space-y-3">
82
+ <div class="flex items-center space-x-2">
83
+ <%= render M9sh::CheckboxComponent.new(name: "preferences[]", value: "email", id: "email_notifications") %>
84
+ <%= render M9sh::LabelComponent.new(for_id: "email_notifications") do %>
85
+ Email notifications
86
+ <% end %>
87
+ </div>
88
+ <div class="flex items-center space-x-2">
89
+ <%= render M9sh::CheckboxComponent.new(name: "preferences[]", value: "sms", id: "sms_notifications", checked: true) %>
90
+ <%= render M9sh::LabelComponent.new(for_id: "sms_notifications") do %>
91
+ SMS notifications
92
+ <% end %>
93
+ </div>
94
+ <div class="flex items-center space-x-2">
95
+ <%= render M9sh::CheckboxComponent.new(name: "preferences[]", value: "push", id: "push_notifications") %>
96
+ <%= render M9sh::LabelComponent.new(for_id: "push_notifications") do %>
97
+ Push notifications
98
+ <% end %>
99
+ </div>
100
+ <div class="flex items-center space-x-2">
101
+ <%= render M9sh::CheckboxComponent.new(name: "preferences[]", value: "newsletter", id: "newsletter", checked: true) %>
102
+ <%= render M9sh::LabelComponent.new(for_id: "newsletter") do %>
103
+ Weekly newsletter
104
+ <% end %>
105
+ </div>
106
+ </div>
107
+ <% end %>
108
+
109
+ <%= render Docs::ComponentPreviewComponent.new(
110
+ title: "Multiple Checkboxes",
111
+ preview_content: multiple_html,
112
+ code: checkbox_multiple_code,
113
+ ai_command: checkbox_multiple_code
114
+ ) %>
115
+
116
+ <!-- Form Integration Example -->
117
+ <% form_html = capture do %>
118
+ <div class="border rounded-lg p-6 max-w-md">
119
+ <h3 class="text-lg font-semibold mb-4">Account Settings</h3>
120
+ <div class="space-y-4">
121
+ <div class="flex items-start space-x-2">
122
+ <%= render M9sh::CheckboxComponent.new(name: "account[two_factor]", id: "two_factor", checked: true) %>
123
+ <div class="grid gap-1.5 leading-none">
124
+ <%= render M9sh::LabelComponent.new(for_id: "two_factor", class: "font-medium") do %>
125
+ Enable two-factor authentication
126
+ <% end %>
127
+ <p class="text-sm text-muted-foreground">
128
+ Add an extra layer of security to your account.
129
+ </p>
130
+ </div>
131
+ </div>
132
+ <div class="flex items-start space-x-2">
133
+ <%= render M9sh::CheckboxComponent.new(name: "account[public_profile]", id: "public_profile") %>
134
+ <div class="grid gap-1.5 leading-none">
135
+ <%= render M9sh::LabelComponent.new(for_id: "public_profile", class: "font-medium") do %>
136
+ Public profile
137
+ <% end %>
138
+ <p class="text-sm text-muted-foreground">
139
+ Make your profile visible to everyone.
140
+ </p>
141
+ </div>
142
+ </div>
143
+ <div class="flex items-start space-x-2">
144
+ <%= render M9sh::CheckboxComponent.new(name: "account[marketing]", id: "marketing") %>
145
+ <div class="grid gap-1.5 leading-none">
146
+ <%= render M9sh::LabelComponent.new(for_id: "marketing", class: "font-medium") do %>
147
+ Marketing emails
148
+ <% end %>
149
+ <p class="text-sm text-muted-foreground">
150
+ Receive emails about new products and features.
151
+ </p>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ <% end %>
157
+
158
+ <%= render Docs::ComponentPreviewComponent.new(
159
+ title: "Form Integration",
160
+ preview_content: form_html,
161
+ code: checkbox_form_code,
162
+ ai_command: checkbox_form_code
163
+ ) %>
164
+ <% end %>
165
+ <% page.with_api do %>
166
+ <%= render Docs::PropTableComponent.new(
167
+ props: [
168
+ {
169
+ name: "name",
170
+ type: "String",
171
+ default: "nil",
172
+ description: "The name attribute for the checkbox input element"
173
+ },
174
+ {
175
+ name: "checked",
176
+ type: "Boolean",
177
+ default: "false",
178
+ description: "Whether the checkbox is checked by default"
179
+ },
180
+ {
181
+ name: "value",
182
+ type: "String",
183
+ default: '"1"',
184
+ description: "The value attribute for the checkbox input element"
185
+ },
186
+ {
187
+ name: "disabled",
188
+ type: "Boolean",
189
+ default: "false",
190
+ description: "Whether the checkbox is disabled"
191
+ },
192
+ {
193
+ name: "id",
194
+ type: "String",
195
+ default: "nil",
196
+ description: "The id attribute for the checkbox input element (useful for associating with labels)"
197
+ }
198
+ ]
199
+ ) %>
200
+
201
+ <div class="mt-6 space-y-2">
202
+ <h3 class="text-lg font-semibold">Additional Notes</h3>
203
+ <ul class="list-disc list-inside space-y-2 text-sm text-muted-foreground">
204
+ <li>The checkbox component includes a Stimulus controller (m9sh--checkbox) for enhanced interactivity</li>
205
+ <li>The component automatically manages the data-state attribute for checked/unchecked states</li>
206
+ <li>All additional HTML attributes can be passed via extra_attrs and will be applied to the input element</li>
207
+ <li>The checkbox follows the WAI-ARIA design pattern for accessibility</li>
208
+ <li>For multiple checkboxes with the same name, use array notation (e.g., name: "preferences[]")</li>
209
+ </ul>
210
+ </div>
211
+ <% end %>
212
+ <% end %>