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,254 @@
1
+ <%= render Docs::ComponentPageComponent.new(title: "Input") do |page| %>
2
+ <% page.with_header(
3
+ name: "Input",
4
+ description: "Displays a form input field with customizable types, placeholders, and states."
5
+ ) %>
6
+
7
+ <% page.with_installation(component_name: "input") %>
8
+
9
+ <% page.with_usage do %>
10
+ <%= render Docs::CodeBlockComponent.new(
11
+ code: input_usage_code,
12
+ language: "erb"
13
+ ) %>
14
+ <% end %>
15
+
16
+ <% page.with_examples do %>
17
+ <!-- Default Input Example -->
18
+ <% default_html = capture do %>
19
+ <div class="w-full max-w-sm">
20
+ <%= render M9sh::InputComponent.new(
21
+ type: "text",
22
+ placeholder: "Enter text..."
23
+ ) %>
24
+ </div>
25
+ <% end %>
26
+
27
+ <%= render Docs::ComponentPreviewComponent.new(
28
+ title: "Default Input",
29
+ preview_content: default_html,
30
+ code: input_usage_code,
31
+ ai_command: input_usage_code
32
+ ) %>
33
+
34
+ <!-- Input Types Example -->
35
+ <% types_html = capture do %>
36
+ <div class="w-full max-w-sm space-y-4">
37
+ <%= render M9sh::InputComponent.new(
38
+ type: "text",
39
+ placeholder: "Text input"
40
+ ) %>
41
+
42
+ <%= render M9sh::InputComponent.new(
43
+ type: "email",
44
+ placeholder: "Email input"
45
+ ) %>
46
+
47
+ <%= render M9sh::InputComponent.new(
48
+ type: "password",
49
+ placeholder: "Password input"
50
+ ) %>
51
+
52
+ <%= render M9sh::InputComponent.new(
53
+ type: "number",
54
+ placeholder: "Number input"
55
+ ) %>
56
+ </div>
57
+ <% end %>
58
+
59
+ <%= render Docs::ComponentPreviewComponent.new(
60
+ title: "Input Types",
61
+ preview_content: types_html,
62
+ code: input_types_code,
63
+ ai_command: input_types_code
64
+ ) %>
65
+
66
+ <!-- Input with Label Example -->
67
+ <% with_label_html = capture do %>
68
+ <div class="w-full max-w-sm space-y-2">
69
+ <%= render M9sh::LabelComponent.new(for_id: "email") do %>
70
+ Email
71
+ <% end %>
72
+ <%= render M9sh::InputComponent.new(
73
+ id: "email",
74
+ type: "email",
75
+ placeholder: "Enter your email"
76
+ ) %>
77
+ </div>
78
+ <% end %>
79
+
80
+ <%= render Docs::ComponentPreviewComponent.new(
81
+ title: "Input with Label",
82
+ preview_content: with_label_html,
83
+ code: input_with_label_code,
84
+ ai_command: input_with_label_code
85
+ ) %>
86
+
87
+ <!-- Disabled Input Example -->
88
+ <% disabled_html = capture do %>
89
+ <div class="w-full max-w-sm">
90
+ <%= render M9sh::InputComponent.new(
91
+ type: "text",
92
+ placeholder: "Disabled input",
93
+ disabled: true
94
+ ) %>
95
+ </div>
96
+ <% end %>
97
+
98
+ <%= render Docs::ComponentPreviewComponent.new(
99
+ title: "Disabled State",
100
+ preview_content: disabled_html,
101
+ code: input_disabled_code,
102
+ ai_command: input_disabled_code
103
+ ) %>
104
+
105
+ <!-- Input with Placeholder Example -->
106
+ <% placeholder_html = capture do %>
107
+ <div class="w-full max-w-sm">
108
+ <%= render M9sh::InputComponent.new(
109
+ type: "text",
110
+ placeholder: "This is a placeholder..."
111
+ ) %>
112
+ </div>
113
+ <% end %>
114
+
115
+ <%= render Docs::ComponentPreviewComponent.new(
116
+ title: "With Placeholder",
117
+ preview_content: placeholder_html,
118
+ code: input_placeholder_code,
119
+ ai_command: input_placeholder_code
120
+ ) %>
121
+
122
+ <!-- Input with Value Example -->
123
+ <% value_html = capture do %>
124
+ <div class="w-full max-w-sm">
125
+ <%= render M9sh::InputComponent.new(
126
+ type: "text",
127
+ value: "Pre-filled value",
128
+ placeholder: "Enter text..."
129
+ ) %>
130
+ </div>
131
+ <% end %>
132
+
133
+ <%= render Docs::ComponentPreviewComponent.new(
134
+ title: "With Default Value",
135
+ preview_content: value_html,
136
+ code: input_value_code,
137
+ ai_command: input_value_code
138
+ ) %>
139
+
140
+ <!-- File Input Example -->
141
+ <% file_html = capture do %>
142
+ <div class="w-full max-w-sm">
143
+ <%= render M9sh::InputComponent.new(
144
+ type: "file"
145
+ ) %>
146
+ </div>
147
+ <% end %>
148
+
149
+ <%= render Docs::ComponentPreviewComponent.new(
150
+ title: "File Input",
151
+ preview_content: file_html,
152
+ code: input_file_code,
153
+ ai_command: input_file_code
154
+ ) %>
155
+ <% end %>
156
+
157
+ <% page.with_api do %>
158
+ <%= render Docs::PropTableComponent.new(
159
+ props: [
160
+ {
161
+ name: "type",
162
+ type: "String",
163
+ default: '"text"',
164
+ description: "The input type (text, email, password, number, file, etc.). Accepts any valid HTML input type."
165
+ },
166
+ {
167
+ name: "name",
168
+ type: "String",
169
+ default: "nil",
170
+ description: "The name attribute for the input field, used when submitting forms."
171
+ },
172
+ {
173
+ name: "value",
174
+ type: "String",
175
+ default: "nil",
176
+ description: "The default value for the input field."
177
+ },
178
+ {
179
+ name: "placeholder",
180
+ type: "String",
181
+ default: "nil",
182
+ description: "Placeholder text displayed when the input is empty."
183
+ },
184
+ {
185
+ name: "disabled",
186
+ type: "Boolean",
187
+ default: "false",
188
+ description: "Whether the input is disabled. Disabled inputs cannot be edited or submitted."
189
+ },
190
+ {
191
+ name: "**extra_attrs",
192
+ type: "Hash",
193
+ default: "{}",
194
+ description: "Additional HTML attributes to apply to the input element (e.g., id, class, data attributes, required, readonly, etc.)."
195
+ }
196
+ ]
197
+ ) %>
198
+
199
+ <div class="mt-6 space-y-2">
200
+ <h3 class="text-lg font-semibold">Styling</h3>
201
+ <p class="text-sm text-muted-foreground">
202
+ The input component includes comprehensive styling with:
203
+ </p>
204
+ <ul class="list-disc list-inside space-y-1 text-sm text-muted-foreground">
205
+ <li>Rounded borders with <code class="text-xs bg-muted px-1.5 py-0.5 rounded">border-input</code> color</li>
206
+ <li>Transparent background that adapts to theme</li>
207
+ <li>Focus ring with <code class="text-xs bg-muted px-1.5 py-0.5 rounded">focus-visible:ring-1</code></li>
208
+ <li>Smooth transitions on color changes</li>
209
+ <li>File input styling with <code class="text-xs bg-muted px-1.5 py-0.5 rounded">file:</code> pseudo-element modifiers</li>
210
+ <li>Placeholder styling with muted foreground color</li>
211
+ <li>Disabled state with reduced opacity and not-allowed cursor</li>
212
+ </ul>
213
+ </div>
214
+
215
+ <div class="mt-6 space-y-2">
216
+ <h3 class="text-lg font-semibold">Accessibility</h3>
217
+ <ul class="list-disc list-inside space-y-1 text-sm text-muted-foreground">
218
+ <li>Supports all standard HTML input types for proper semantics</li>
219
+ <li>Use with <code class="text-xs bg-muted px-1.5 py-0.5 rounded">LabelComponent</code> to associate labels with inputs</li>
220
+ <li>Disabled state properly prevents interaction and updates cursor</li>
221
+ <li>Focus-visible ring ensures keyboard navigation visibility</li>
222
+ <li>Placeholder text uses muted color for better accessibility</li>
223
+ </ul>
224
+ </div>
225
+
226
+ <div class="mt-6 space-y-2">
227
+ <h3 class="text-lg font-semibold">Common Input Types</h3>
228
+ <div class="grid grid-cols-2 gap-4 text-sm">
229
+ <div>
230
+ <h4 class="font-semibold mb-2">Text Types</h4>
231
+ <ul class="list-disc list-inside space-y-1 text-muted-foreground">
232
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">text</code> - Standard text input</li>
233
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">email</code> - Email address input</li>
234
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">password</code> - Password input (hidden)</li>
235
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">tel</code> - Telephone number</li>
236
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">url</code> - URL input</li>
237
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">search</code> - Search input</li>
238
+ </ul>
239
+ </div>
240
+ <div>
241
+ <h4 class="font-semibold mb-2">Other Types</h4>
242
+ <ul class="list-disc list-inside space-y-1 text-muted-foreground">
243
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">number</code> - Numeric input</li>
244
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">date</code> - Date picker</li>
245
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">time</code> - Time picker</li>
246
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">datetime-local</code> - Date and time</li>
247
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">file</code> - File upload</li>
248
+ <li><code class="text-xs bg-muted px-1.5 py-0.5 rounded">color</code> - Color picker</li>
249
+ </ul>
250
+ </div>
251
+ </div>
252
+ </div>
253
+ <% end %>
254
+ <% end %>
@@ -0,0 +1,128 @@
1
+ <%= render Docs::ComponentPageComponent.new(title: "Label") do |page| %>
2
+ <% page.with_header(
3
+ name: "Label",
4
+ description: "Renders an accessible label associated with form controls."
5
+ ) %>
6
+
7
+ <% page.with_installation(component_name: "label") %>
8
+
9
+ <% page.with_usage do %>
10
+ <%= render Docs::CodeBlockComponent.new(
11
+ code: label_usage_code,
12
+ language: "erb"
13
+ ) %>
14
+ <% end %>
15
+
16
+ <% page.with_examples do %>
17
+ <!-- Basic Label Example -->
18
+ <% basic_html = capture do %>
19
+ <%= render M9sh::LabelComponent.new(for_id: "email") do %>
20
+ Email
21
+ <% end %>
22
+ <% end %>
23
+
24
+ <%= render Docs::ComponentPreviewComponent.new(
25
+ title: "Basic Label",
26
+ preview_content: basic_html,
27
+ code: label_usage_code,
28
+ ai_command: label_usage_code
29
+ ) %>
30
+
31
+ <!-- Label with Input Field Example -->
32
+ <% with_input_html = capture do %>
33
+ <div class="space-y-2 w-full max-w-sm">
34
+ <%= render M9sh::LabelComponent.new(for_id: "email") do %>
35
+ Email
36
+ <% end %>
37
+ <input
38
+ id="email"
39
+ type="email"
40
+ placeholder="Enter your email"
41
+ class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
42
+ />
43
+ </div>
44
+ <% end %>
45
+
46
+ <%= render Docs::ComponentPreviewComponent.new(
47
+ title: "Label with Input Field",
48
+ preview_content: with_input_html,
49
+ code: label_with_input_code,
50
+ ai_command: label_with_input_code
51
+ ) %>
52
+
53
+ <!-- Label with Required Indicator Example -->
54
+ <% required_html = capture do %>
55
+ <div class="space-y-2 w-full max-w-sm">
56
+ <%= render M9sh::LabelComponent.new(for_id: "username") do %>
57
+ Username <span class="text-destructive">*</span>
58
+ <% end %>
59
+ <input
60
+ id="username"
61
+ type="text"
62
+ placeholder="Enter your username"
63
+ required
64
+ class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
65
+ />
66
+ </div>
67
+ <% end %>
68
+
69
+ <%= render Docs::ComponentPreviewComponent.new(
70
+ title: "Label with Required Indicator",
71
+ preview_content: required_html,
72
+ code: label_with_required_code,
73
+ ai_command: label_with_required_code
74
+ ) %>
75
+
76
+ <!-- Label with Disabled Input Example -->
77
+ <% disabled_html = capture do %>
78
+ <div class="space-y-2 w-full max-w-sm group" data-disabled="true">
79
+ <%= render M9sh::LabelComponent.new(for_id: "disabled-input") do %>
80
+ Disabled Field
81
+ <% end %>
82
+ <input
83
+ id="disabled-input"
84
+ type="text"
85
+ placeholder="This field is disabled"
86
+ disabled
87
+ class="flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50"
88
+ />
89
+ </div>
90
+ <% end %>
91
+
92
+ <%= render Docs::ComponentPreviewComponent.new(
93
+ title: "Label with Disabled Input",
94
+ preview_content: disabled_html,
95
+ code: label_with_disabled_code,
96
+ ai_command: label_with_disabled_code
97
+ ) %>
98
+ <% end %>
99
+
100
+ <% page.with_api do %>
101
+ <%= render Docs::PropTableComponent.new(
102
+ props: [
103
+ {
104
+ name: "for_id",
105
+ type: "String",
106
+ default: "nil",
107
+ description: "The ID of the form control this label is associated with. Sets the HTML 'for' attribute."
108
+ },
109
+ {
110
+ name: "**extra_attrs",
111
+ type: "Hash",
112
+ default: "{}",
113
+ description: "Additional HTML attributes to apply to the label element (e.g., class, data attributes)."
114
+ }
115
+ ]
116
+ ) %>
117
+
118
+ <div class="mt-6 space-y-2">
119
+ <h3 class="text-lg font-semibold">Accessibility</h3>
120
+ <ul class="list-disc list-inside space-y-1 text-sm text-muted-foreground">
121
+ <li>The label uses the <code class="text-xs bg-muted px-1.5 py-0.5 rounded">for</code> attribute to associate with form controls</li>
122
+ <li>Labels are not selectable using the <code class="text-xs bg-muted px-1.5 py-0.5 rounded">select-none</code> class</li>
123
+ <li>Automatically responds to disabled state via <code class="text-xs bg-muted px-1.5 py-0.5 rounded">group-data-[disabled=true]</code> and <code class="text-xs bg-muted px-1.5 py-0.5 rounded">peer-disabled</code> selectors</li>
124
+ <li>Includes a <code class="text-xs bg-muted px-1.5 py-0.5 rounded">data-slot="label"</code> attribute for component composition</li>
125
+ </ul>
126
+ </div>
127
+ <% end %>
128
+ <% end %>