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,240 @@
1
+ <%= render M9sh::NavbarComponent.new(sticky: local_assigns[:sticky] || false, transparent: true, container: false, class_name: "navbar-blur") do |navbar| %>
2
+ <% # Left toggle button for sidebar %>
3
+ <% if local_assigns[:show_left_toggle] %>
4
+ <% navbar.with_left_action do %>
5
+ <button class="md:hidden flex-shrink-0 p-2 hover:bg-accent transition-colors rounded-lg"
6
+ data-backdrop-target="leftToggle"
7
+ data-action="click->backdrop#toggleLeft"
8
+ aria-label="Toggle left sidebar">
9
+ <%= render M9sh::IconComponent.new(name: "chevron-right", size: "20", class_name: "transition-transform duration-300") %>
10
+ </button>
11
+ <% end %>
12
+ <% end %>
13
+
14
+ <% navbar.with_brand do %>
15
+ <a href="/" class="flex items-center space-x-2 group">
16
+ <span class="font-bold text-xl text-foreground">m9sh/ui</span>
17
+ </a>
18
+ <% end %>
19
+
20
+ <% navbar.with_navigation do %>
21
+ <nav class="flex items-center gap-1">
22
+ <a href="/docs" class="px-3 py-2 text-sm font-medium text-foreground rounded-lg hover:bg-accent transition-colors">
23
+ Components
24
+ </a>
25
+ <a href="/blocks" class="px-3 py-2 text-sm font-medium text-foreground rounded-lg hover:bg-accent transition-colors">
26
+ Blocks
27
+ </a>
28
+ </nav>
29
+ <% end %>
30
+
31
+ <% navbar.with_actions do %>
32
+ <%= render M9sh::ButtonComponent.new(variant: :ghost, size: :icon) do %>
33
+ <%= render M9sh::IconComponent.new(name: "search", size: "20") %>
34
+ <% end %>
35
+ <% end %>
36
+
37
+ <% navbar.with_actions do %>
38
+ <a href="https://github.com" target="_blank" rel="noreferrer">
39
+ <%= render M9sh::ButtonComponent.new(variant: :ghost, size: :icon) do %>
40
+ <%= render M9sh::IconComponent.new(name: "github", size: "20") %>
41
+ <% end %>
42
+ </a>
43
+ <% end %>
44
+
45
+ <% navbar.with_actions do %>
46
+ <div class="relative flex items-center border border-border rounded-lg overflow-hidden">
47
+ <button data-action="click->color-theme#previous"
48
+ class="p-2 hover:bg-accent transition-colors text-foreground"
49
+ title="Previous color theme">
50
+ <%= render M9sh::IconComponent.new(name: "chevron-left", size: "16") %>
51
+ </button>
52
+ <div class="h-5 w-px bg-border"></div>
53
+ <button data-action="click->color-theme#toggleDropdown"
54
+ class="px-3 py-2 hover:bg-accent transition-colors text-foreground min-w-[80px] text-sm font-medium"
55
+ title="Select color theme">
56
+ <span data-color-theme-target="currentTheme">Neutral</span>
57
+ </button>
58
+ <div class="h-5 w-px bg-border"></div>
59
+ <button data-action="click->color-theme#next"
60
+ class="p-2 hover:bg-accent transition-colors text-foreground"
61
+ title="Next color theme">
62
+ <%= render M9sh::IconComponent.new(name: "chevron-right", size: "16") %>
63
+ </button>
64
+
65
+ <!-- Dropdown Menu -->
66
+ <div data-color-theme-target="dropdown"
67
+ class="hidden absolute top-full right-0 mt-2 w-40 bg-popover border border-border rounded-lg shadow-lg overflow-hidden z-50">
68
+ <div class="py-1">
69
+ <button data-action="click->color-theme#selectTheme"
70
+ data-theme="neutral"
71
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
72
+ <span>Neutral</span>
73
+ <div class="flex gap-1">
74
+ <div class="w-3 h-3 rounded-full bg-zinc-400"></div>
75
+ </div>
76
+ </button>
77
+ <button data-action="click->color-theme#selectTheme"
78
+ data-theme="indigo"
79
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
80
+ <span>Indigo</span>
81
+ <div class="flex gap-1">
82
+ <div class="w-3 h-3 rounded-full bg-indigo-500"></div>
83
+ </div>
84
+ </button>
85
+ <button data-action="click->color-theme#selectTheme"
86
+ data-theme="party"
87
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
88
+ <span>Party</span>
89
+ <div class="flex gap-1">
90
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-pink-500 via-purple-500 to-indigo-500"></div>
91
+ </div>
92
+ </button>
93
+ <button data-action="click->color-theme#selectTheme"
94
+ data-theme="sunset"
95
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
96
+ <span>Sunset</span>
97
+ <div class="flex gap-1">
98
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-orange-500 to-red-500"></div>
99
+ </div>
100
+ </button>
101
+ <button data-action="click->color-theme#selectTheme"
102
+ data-theme="ocean"
103
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
104
+ <span>Ocean</span>
105
+ <div class="flex gap-1">
106
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-blue-500 to-cyan-500"></div>
107
+ </div>
108
+ </button>
109
+ <button data-action="click->color-theme#selectTheme"
110
+ data-theme="forest"
111
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
112
+ <span>Forest</span>
113
+ <div class="flex gap-1">
114
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-green-600 to-emerald-500"></div>
115
+ </div>
116
+ </button>
117
+ <button data-action="click->color-theme#selectTheme"
118
+ data-theme="cyberpunk"
119
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
120
+ <span>Cyberpunk</span>
121
+ <div class="flex gap-1">
122
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-purple-500 to-cyan-500"></div>
123
+ </div>
124
+ </button>
125
+ <button data-action="click->color-theme#selectTheme"
126
+ data-theme="thunder"
127
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
128
+ <span>Thunder</span>
129
+ <div class="flex gap-1">
130
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-yellow-400 to-black"></div>
131
+ </div>
132
+ </button>
133
+ <button data-action="click->color-theme#selectTheme"
134
+ data-theme="rose"
135
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
136
+ <span>Rose</span>
137
+ <div class="flex gap-1">
138
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-pink-400 to-rose-600"></div>
139
+ </div>
140
+ </button>
141
+ <button data-action="click->color-theme#selectTheme"
142
+ data-theme="miami"
143
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
144
+ <span>Miami</span>
145
+ <div class="flex gap-1">
146
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-pink-500 to-cyan-400"></div>
147
+ </div>
148
+ </button>
149
+ <button data-action="click->color-theme#selectTheme"
150
+ data-theme="lavender"
151
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
152
+ <span>Lavender</span>
153
+ <div class="flex gap-1">
154
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-purple-400 to-violet-500"></div>
155
+ </div>
156
+ </button>
157
+ <button data-action="click->color-theme#selectTheme"
158
+ data-theme="mint"
159
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
160
+ <span>Mint</span>
161
+ <div class="flex gap-1">
162
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-emerald-400 to-yellow-400"></div>
163
+ </div>
164
+ </button>
165
+ <button data-action="click->color-theme#selectTheme"
166
+ data-theme="coral"
167
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
168
+ <span>Coral</span>
169
+ <div class="flex gap-1">
170
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-orange-400 to-cyan-400"></div>
171
+ </div>
172
+ </button>
173
+ <button data-action="click->color-theme#selectTheme"
174
+ data-theme="arctic"
175
+ class="w-full px-4 py-2 text-sm text-left hover:bg-accent transition-colors flex items-center justify-between">
176
+ <span>Arctic</span>
177
+ <div class="flex gap-1">
178
+ <div class="w-3 h-3 rounded-full bg-gradient-to-r from-blue-400 via-purple-400 to-indigo-500"></div>
179
+ </div>
180
+ </button>
181
+ </div>
182
+ </div>
183
+ </div>
184
+ <% end %>
185
+
186
+ <% navbar.with_actions do %>
187
+ <%= render M9sh::ButtonComponent.new(variant: :ghost, size: :icon, data: { action: "click->theme#openCustomizer" }, onclick: "document.getElementById('color-customizer-trigger').click()") do %>
188
+ <%= render M9sh::IconComponent.new(name: "paintbrush", size: "20") %>
189
+ <% end %>
190
+ <% end %>
191
+
192
+ <% navbar.with_actions do %>
193
+ <%= render M9sh::ButtonComponent.new(variant: :ghost, size: :icon, data: { action: "click->theme#toggle" }) do %>
194
+ <span class="relative inline-flex items-center justify-center w-5 h-5">
195
+ <%= render M9sh::IconComponent.new(name: "sun", size: "20", class_name: "absolute inset-0 rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0") %>
196
+ <%= render M9sh::IconComponent.new(name: "moon", size: "20", class_name: "absolute inset-0 rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100") %>
197
+ </span>
198
+ <% end %>
199
+ <% end %>
200
+
201
+ <% # Right toggle button for sidebar %>
202
+ <% if local_assigns[:show_right_toggle] %>
203
+ <% navbar.with_right_action do %>
204
+ <button class="md:hidden flex-shrink-0 p-2 hover:bg-accent transition-colors rounded-lg"
205
+ data-backdrop-target="rightToggle"
206
+ data-action="click->backdrop#toggleRight"
207
+ aria-label="Toggle right sidebar">
208
+ <%= render M9sh::IconComponent.new(name: "chevron-left", size: "20", class_name: "transition-transform duration-300") %>
209
+ </button>
210
+ <% end %>
211
+ <% end %>
212
+
213
+ <% navbar.with_mobile_menu do %>
214
+ <%= render M9sh::DropdownMenuItemComponent.new(href: "/docs") do %>
215
+ <%= render M9sh::IconComponent.new(name: "home", size: "16", class_name: "mr-2") %>
216
+ Components
217
+ <% end %>
218
+ <%= render M9sh::DropdownMenuItemComponent.new(href: "/blocks") do %>
219
+ <%= render M9sh::IconComponent.new(name: "layout", size: "16", class_name: "mr-2") %>
220
+ Blocks
221
+ <% end %>
222
+ <%= render M9sh::DropdownMenuSeparatorComponent.new %>
223
+ <button data-action="click->theme#toggle"
224
+ class="w-full relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm text-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
225
+ <%= render M9sh::IconComponent.new(name: "sun", size: "16", class_name: "mr-2") %>
226
+ Toggle Theme
227
+ </button>
228
+ <button onclick="document.getElementById('color-customizer-trigger').click()"
229
+ class="w-full relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm text-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
230
+ <%= render M9sh::IconComponent.new(name: "paintbrush", size: "16", class_name: "mr-2") %>
231
+ Customize Colors
232
+ </button>
233
+ <%= render M9sh::DropdownMenuSeparatorComponent.new %>
234
+ <a href="https://github.com" target="_blank" rel="noreferrer"
235
+ class="relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm text-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
236
+ <%= render M9sh::IconComponent.new(name: "github", size: "16", class_name: "mr-2") %>
237
+ GitHub
238
+ </a>
239
+ <% end %>
240
+ <% end %>
@@ -0,0 +1,69 @@
1
+ <%= render M9sh::NavbarComponent.new(
2
+ sticky: true,
3
+ transparent: true,
4
+ container: false,
5
+ border: true
6
+ ) do |navbar| %>
7
+ <% navbar.with_brand do %>
8
+ <a href="/" class="flex items-center space-x-2 group">
9
+ <span class="font-bold text-xl text-foreground">m9sh/ui</span>
10
+ </a>
11
+ <% end %>
12
+
13
+ <% navbar.with_navigation do %>
14
+ <nav class="flex items-center gap-1">
15
+ <%= link_to "/docs", class: "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 text-foreground hover:bg-accent hover:text-accent-foreground h-9 px-4 py-2" do %>
16
+ Components
17
+ <% end %>
18
+ <%= link_to "/blocks", class: "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 text-foreground hover:bg-accent hover:text-accent-foreground h-9 px-4 py-2" do %>
19
+ Blocks
20
+ <% end %>
21
+ </nav>
22
+ <% end %>
23
+
24
+ <% navbar.with_actions do %>
25
+ <a href="https://github.com" target="_blank" rel="noreferrer"
26
+ class="hidden sm:inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 text-foreground hover:bg-accent hover:text-accent-foreground h-9 w-9">
27
+ <%= render M9sh::IconComponent.new(name: "github", size: "18") %>
28
+ <span class="sr-only">GitHub</span>
29
+ </a>
30
+ <% end %>
31
+
32
+ <% navbar.with_actions do %>
33
+ <button id="theme-toggle"
34
+ class="inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 text-foreground hover:bg-accent hover:text-accent-foreground h-9 w-9 relative">
35
+ <%= render M9sh::IconComponent.new(name: "sun", size: "18", class_name: "rotate-0 scale-100 transition-all dark:-rotate-90 dark:scale-0") %>
36
+ <%= render M9sh::IconComponent.new(name: "moon", size: "18", class_name: "absolute rotate-90 scale-0 transition-all dark:rotate-0 dark:scale-100") %>
37
+ <span class="sr-only">Toggle theme</span>
38
+ </button>
39
+ <% end %>
40
+
41
+ <% navbar.with_mobile_menu do %>
42
+ <%= render M9sh::DropdownMenuItemComponent.new(href: "/docs") do %>
43
+ Components
44
+ <% end %>
45
+ <%= render M9sh::DropdownMenuItemComponent.new(href: "/blocks") do %>
46
+ Blocks
47
+ <% end %>
48
+ <%= render M9sh::DropdownMenuSeparatorComponent.new %>
49
+ <a href="https://github.com" target="_blank" rel="noreferrer"
50
+ class="relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm text-foreground outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
51
+ <%= render M9sh::IconComponent.new(name: "github", size: "16", class_name: "mr-2") %>
52
+ GitHub
53
+ </a>
54
+ <% end %>
55
+ <% end %>
56
+
57
+ <script>
58
+ // Setup dark mode toggle
59
+ document.addEventListener('DOMContentLoaded', function() {
60
+ const toggle = document.getElementById('theme-toggle');
61
+ if (toggle) {
62
+ toggle.addEventListener('click', function() {
63
+ const html = document.documentElement;
64
+ const isDark = html.classList.toggle('dark');
65
+ localStorage.setItem('theme', isDark ? 'dark' : 'light');
66
+ });
67
+ }
68
+ });
69
+ </script>
@@ -0,0 +1,38 @@
1
+ <!-- Components Grid Section -->
2
+ <section class="py-16 md:py-24">
3
+ <div class="container mx-auto px-4 md:px-6">
4
+ <!-- Section Header -->
5
+ <div class="mb-12">
6
+ <h2 class="text-3xl font-bold tracking-tight text-foreground mb-3">
7
+ Components
8
+ </h2>
9
+ <p class="text-muted-foreground max-w-2xl">
10
+ Beautifully designed components built with ViewComponent and Tailwind CSS. Copy, paste, and customize.
11
+ </p>
12
+ </div>
13
+
14
+ <!-- Components Grid -->
15
+ <div class="grid gap-4 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
16
+ <% @components.each do |component| %>
17
+ <%= link_to docs_component_path(component), class: "group block p-6 rounded-lg border border-border bg-card hover:border-primary/50 hover:bg-accent/50 transition-all duration-200" do %>
18
+ <h3 class="font-semibold text-foreground group-hover:text-primary transition-colors mb-2">
19
+ <%= component.titleize.gsub('_', ' ') %>
20
+ </h3>
21
+ <p class="text-sm text-muted-foreground line-clamp-2">
22
+ <%= @descriptions[component] %>
23
+ </p>
24
+ <% end %>
25
+ <% end %>
26
+ </div>
27
+
28
+ <!-- View All Link -->
29
+ <div class="mt-8">
30
+ <%= link_to docs_path, class: "inline-flex items-center text-sm font-medium text-muted-foreground hover:text-foreground transition-colors" do %>
31
+ View all components
32
+ <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-1 h-4 w-4">
33
+ <path d="m9 18 6-6-6-6"/>
34
+ </svg>
35
+ <% end %>
36
+ </div>
37
+ </div>
38
+ </section>
@@ -0,0 +1,59 @@
1
+ <!-- Features Section -->
2
+ <section class="py-16 md:py-24 bg-background">
3
+ <div class="container mx-auto px-4 md:px-6">
4
+ <div class="mx-auto max-w-[58rem] text-center mb-12">
5
+ <h2 class="text-3xl font-bold tracking-tight text-foreground sm:text-4xl">
6
+ Why Choose m9sh Components?
7
+ </h2>
8
+ <p class="mt-4 text-lg text-muted-foreground">
9
+ Everything you need to build modern Rails applications with confidence
10
+ </p>
11
+ </div>
12
+
13
+ <div class="grid gap-8 md:gap-12 lg:grid-cols-3 max-w-6xl mx-auto">
14
+ <div class="relative space-y-4">
15
+ <div class="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
16
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-6 w-6 text-primary">
17
+ <path d="M12 2v20M2 12h20"/>
18
+ </svg>
19
+ </div>
20
+ <div class="space-y-2">
21
+ <h3 class="text-xl font-semibold text-foreground">Rails Native</h3>
22
+ <p class="text-muted-foreground leading-relaxed">
23
+ Built specifically for Rails with ViewComponents, Stimulus, and Turbo. No external dependencies required.
24
+ </p>
25
+ </div>
26
+ </div>
27
+
28
+ <div class="relative space-y-4">
29
+ <div class="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
30
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-6 w-6 text-primary">
31
+ <rect width="14" height="14" x="8" y="8" rx="2" ry="2"/>
32
+ <path d="M4 16c-1.11 0-2-.9-2-2V4c0-1.11.89-2 2-2h10c1.11 0 2 .89 2 2"/>
33
+ </svg>
34
+ </div>
35
+ <div class="space-y-2">
36
+ <h3 class="text-xl font-semibold text-foreground">Copy & Paste</h3>
37
+ <p class="text-muted-foreground leading-relaxed">
38
+ No package dependencies. Copy the code into your project and customize it to match your needs.
39
+ </p>
40
+ </div>
41
+ </div>
42
+
43
+ <div class="relative space-y-4">
44
+ <div class="flex h-12 w-12 items-center justify-center rounded-lg bg-primary/10">
45
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-6 w-6 text-primary">
46
+ <circle cx="12" cy="12" r="10"/>
47
+ <path d="M12 6v6l4 2"/>
48
+ </svg>
49
+ </div>
50
+ <div class="space-y-2">
51
+ <h3 class="text-xl font-semibold text-foreground">Accessible</h3>
52
+ <p class="text-muted-foreground leading-relaxed">
53
+ Built with ARIA attributes and keyboard navigation. Follows WAI-ARIA design patterns for accessibility.
54
+ </p>
55
+ </div>
56
+ </div>
57
+ </div>
58
+ </div>
59
+ </section>
@@ -0,0 +1,195 @@
1
+ <!-- Forms Section -->
2
+ <section class="py-16 md:py-24 bg-background border-t border-border">
3
+ <div class="container mx-auto px-4 md:px-6">
4
+ <div class="mx-auto max-w-[58rem] text-center mb-12">
5
+ <h2 class="text-3xl font-bold tracking-tight text-foreground sm:text-4xl">
6
+ Form Components in Action
7
+ </h2>
8
+ <p class="mt-4 text-lg text-muted-foreground">
9
+ Complete form examples showcasing authentication, payment, and settings interfaces
10
+ </p>
11
+ </div>
12
+
13
+ <div class="grid gap-6 lg:grid-cols-2 max-w-6xl mx-auto">
14
+ <!-- Create Account Form -->
15
+ <%= render M9sh::CardComponent.new do |card| %>
16
+ <% card.with_header do %>
17
+ <h3 class="text-lg font-semibold text-foreground">Create an account</h3>
18
+ <p class="text-sm text-muted-foreground mt-2">
19
+ Enter your email below to create your account
20
+ </p>
21
+ <% end %>
22
+ <% card.with_body do %>
23
+ <div class="space-y-4">
24
+ <div class="grid gap-2">
25
+ <%= render M9sh::ButtonComponent.new(variant: :outline, class: "w-full") do %>
26
+ <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" viewBox="0 0 24 24" class="mr-2">
27
+ <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
28
+ </svg>
29
+ Continue with GitHub
30
+ <% end %>
31
+ <%= render M9sh::ButtonComponent.new(variant: :outline, class: "w-full") do %>
32
+ <svg viewBox="0 0 24 24" class="mr-2 h-4 w-4">
33
+ <path fill="currentColor" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"/>
34
+ <path fill="currentColor" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/>
35
+ <path fill="currentColor" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/>
36
+ <path fill="currentColor" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/>
37
+ </svg>
38
+ Continue with Google
39
+ <% end %>
40
+ </div>
41
+ <div class="relative my-4">
42
+ <div class="absolute inset-0 flex items-center">
43
+ <%= render M9sh::SeparatorComponent.new %>
44
+ </div>
45
+ <div class="relative flex justify-center text-xs uppercase">
46
+ <span class="bg-background px-2 text-muted-foreground">Or continue with</span>
47
+ </div>
48
+ </div>
49
+ <div class="grid gap-2">
50
+ <%= render M9sh::InputComponent.new(type: :email, placeholder: "name@example.com") %>
51
+ <%= render M9sh::InputComponent.new(type: :password, placeholder: "Password") %>
52
+ </div>
53
+ <%= render M9sh::ButtonComponent.new(variant: :default, class: "w-full") do %>
54
+ Create Account
55
+ <% end %>
56
+ <p class="text-xs text-center text-muted-foreground">
57
+ By clicking continue, you agree to our
58
+ <a href="#" class="underline hover:text-primary"> Terms of Service</a>
59
+ and
60
+ <a href="#" class="underline hover:text-primary"> Privacy Policy</a>.
61
+ </p>
62
+ </div>
63
+ <% end %>
64
+ <% end %>
65
+
66
+ <!-- Payment Method Form -->
67
+ <%= render M9sh::CardComponent.new do |card| %>
68
+ <% card.with_header do %>
69
+ <h3 class="text-lg font-semibold text-foreground">Payment Method</h3>
70
+ <p class="text-sm text-muted-foreground mt-2">
71
+ Add a new payment method to your account.
72
+ </p>
73
+ <% end %>
74
+ <% card.with_body do %>
75
+ <div class="space-y-4">
76
+ <div class="grid gap-4">
77
+ <div class="grid gap-2">
78
+ <%= render M9sh::LabelComponent.new(for: "card-name") do %>Name<% end %>
79
+ <%= render M9sh::InputComponent.new(id: "card-name", placeholder: "First Last") %>
80
+ </div>
81
+ <div class="grid gap-2">
82
+ <%= render M9sh::LabelComponent.new(for: "card-number") do %>Card number<% end %>
83
+ <%= render M9sh::InputComponent.new(id: "card-number", placeholder: "1234 5678 9012 3456") %>
84
+ </div>
85
+ <div class="grid grid-cols-3 gap-4">
86
+ <div class="grid gap-2">
87
+ <%= render M9sh::LabelComponent.new(for: "month") do %>Month<% end %>
88
+ <%= render M9sh::SelectComponent.new(id: "month") do |select| %>
89
+ <% (1..12).each do |month| %>
90
+ <% select.with_option(value: format("%02d", month)) do %>
91
+ <%= format("%02d", month) %>
92
+ <% end %>
93
+ <% end %>
94
+ <% end %>
95
+ </div>
96
+ <div class="grid gap-2">
97
+ <%= render M9sh::LabelComponent.new(for: "year") do %>Year<% end %>
98
+ <%= render M9sh::SelectComponent.new(id: "year") do |select| %>
99
+ <% (2024..2030).each do |year| %>
100
+ <% select.with_option(value: year.to_s) do %>
101
+ <%= year %>
102
+ <% end %>
103
+ <% end %>
104
+ <% end %>
105
+ </div>
106
+ <div class="grid gap-2">
107
+ <%= render M9sh::LabelComponent.new(for: "cvc") do %>CVC<% end %>
108
+ <%= render M9sh::InputComponent.new(id: "cvc", placeholder: "123") %>
109
+ </div>
110
+ </div>
111
+ </div>
112
+ <%= render M9sh::ButtonComponent.new(variant: :default, class: "w-full") do %>
113
+ Continue
114
+ <% end %>
115
+ </div>
116
+ <% end %>
117
+ <% end %>
118
+
119
+ <!-- Notifications Settings -->
120
+ <%= render M9sh::CardComponent.new do |card| %>
121
+ <% card.with_header do %>
122
+ <h3 class="text-lg font-semibold text-foreground">Notifications</h3>
123
+ <p class="text-sm text-muted-foreground mt-2">
124
+ Choose what you want to be notified about.
125
+ </p>
126
+ <% end %>
127
+ <% card.with_body do %>
128
+ <div class="space-y-4">
129
+ <%= render M9sh::RadioGroupComponent.new(name: "notifications", default_value: "all") do |group| %>
130
+ <% group.with_item(
131
+ value: "all",
132
+ label: "Everything",
133
+ description: "Email me when anything important happens",
134
+ checked: true
135
+ ) %>
136
+ <% group.with_item(
137
+ value: "mentions",
138
+ label: "Available",
139
+ description: "Only when someone mentions me"
140
+ ) %>
141
+ <% group.with_item(
142
+ value: "none",
143
+ label: "Ignoring",
144
+ description: "Turn off all notifications"
145
+ ) %>
146
+ <% end %>
147
+ <%= render M9sh::ButtonComponent.new(variant: :default, class: "w-full mt-4") do %>
148
+ Save preferences
149
+ <% end %>
150
+ </div>
151
+ <% end %>
152
+ <% end %>
153
+
154
+ <!-- Cookie Settings -->
155
+ <%= render M9sh::CardComponent.new do |card| %>
156
+ <% card.with_header do %>
157
+ <h3 class="text-lg font-semibold text-foreground">Cookie Settings</h3>
158
+ <p class="text-sm text-muted-foreground mt-2">
159
+ Manage your cookie settings here.
160
+ </p>
161
+ <% end %>
162
+ <% card.with_body do %>
163
+ <div class="space-y-4">
164
+ <div class="space-y-4">
165
+ <div class="flex items-center justify-between">
166
+ <div class="space-y-0.5">
167
+ <%= render M9sh::LabelComponent.new(for: "necessary") do %>Strictly Necessary<% end %>
168
+ <p class="text-sm text-muted-foreground">These cookies are essential for the website to function properly.</p>
169
+ </div>
170
+ <%= render M9sh::SwitchComponent.new(id: "necessary", checked: true) %>
171
+ </div>
172
+ <div class="flex items-center justify-between">
173
+ <div class="space-y-0.5">
174
+ <%= render M9sh::LabelComponent.new(for: "functional") do %>Functional Cookies<% end %>
175
+ <p class="text-sm text-muted-foreground">These cookies enable personalized features.</p>
176
+ </div>
177
+ <%= render M9sh::SwitchComponent.new(id: "functional") %>
178
+ </div>
179
+ <div class="flex items-center justify-between">
180
+ <div class="space-y-0.5">
181
+ <%= render M9sh::LabelComponent.new(for: "performance") do %>Performance Cookies<% end %>
182
+ <p class="text-sm text-muted-foreground">These cookies help to improve website performance.</p>
183
+ </div>
184
+ <%= render M9sh::SwitchComponent.new(id: "performance") %>
185
+ </div>
186
+ </div>
187
+ <%= render M9sh::ButtonComponent.new(variant: :default, class: "w-full") do %>
188
+ Save preferences
189
+ <% end %>
190
+ </div>
191
+ <% end %>
192
+ <% end %>
193
+ </div>
194
+ </div>
195
+ </section>