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,394 @@
1
+ <%= render Docs::ComponentPageComponent.new(title: "Navbar") do |page| %>
2
+ <% page.with_header(
3
+ name: "Navbar",
4
+ description: "A responsive navigation header component with logo, navigation links, and action buttons."
5
+ ) %>
6
+
7
+ <% page.with_installation(component_name: "navbar") %>
8
+
9
+ <% page.with_usage do %>
10
+ <%= render Docs::CodeBlockComponent.new(
11
+ code: navbar_usage_code,
12
+ language: "erb"
13
+ ) %>
14
+ <% end %>
15
+
16
+ <% page.with_examples do %>
17
+ <div class="space-y-8">
18
+ <div>
19
+ <h3 class="text-lg font-semibold mb-3">Live Example</h3>
20
+ <p class="text-muted-foreground mb-4">
21
+ The NavbarComponent is currently used throughout this application. You can see it in action at the top of this page!
22
+ </p>
23
+ </div>
24
+
25
+ <%= render Docs::ComponentPreviewComponent.new(
26
+ title: "Transparent Navbar",
27
+ code: navbar_transparent_code,
28
+ mobile_optimized: true
29
+ ) do %>
30
+ <div class="w-full bg-gradient-to-br from-blue-50 via-purple-50 to-pink-50 dark:from-blue-950 dark:via-purple-950 dark:to-pink-950 p-8">
31
+ <%= render M9sh::NavbarComponent.new(transparent: true, sticky: false) do |navbar| %>
32
+ <% navbar.with_brand do %>
33
+ <a href="#" class="flex items-center space-x-2">
34
+ <span class="font-bold text-xl text-foreground">Brand</span>
35
+ </a>
36
+ <% end %>
37
+
38
+ <% navbar.with_navigation do %>
39
+ <nav class="flex items-center gap-6">
40
+ <a href="#" class="text-sm font-medium text-foreground hover:text-foreground/80 transition-colors">Home</a>
41
+ <a href="#" class="text-sm font-medium text-foreground hover:text-foreground/80 transition-colors">About</a>
42
+ <a href="#" class="text-sm font-medium text-foreground hover:text-foreground/80 transition-colors">Services</a>
43
+ </nav>
44
+ <% end %>
45
+
46
+ <% navbar.with_actions do %>
47
+ <%= render M9sh::ButtonComponent.new(variant: :ghost, size: :sm) do %>
48
+ Get Started
49
+ <% end %>
50
+ <% end %>
51
+ <% end %>
52
+ </div>
53
+ <% end %>
54
+
55
+ <%= render Docs::ComponentPreviewComponent.new(
56
+ title: "Full Width Navbar",
57
+ code: navbar_full_width_code,
58
+ mobile_optimized: true
59
+ ) do %>
60
+ <div class="w-full">
61
+ <%= render M9sh::NavbarComponent.new(container: false, sticky: false) do |navbar| %>
62
+ <% navbar.with_brand do %>
63
+ <a href="#" class="font-bold text-xl">Full Width</a>
64
+ <% end %>
65
+
66
+ <% navbar.with_navigation do %>
67
+ <nav class="flex items-center gap-6">
68
+ <a href="#" class="text-sm font-medium">Features</a>
69
+ <a href="#" class="text-sm font-medium">Docs</a>
70
+ </nav>
71
+ <% end %>
72
+
73
+ <% navbar.with_actions do %>
74
+ <%= render M9sh::ButtonComponent.new(size: :sm) do %>
75
+ Sign Up
76
+ <% end %>
77
+ <% end %>
78
+ <% end %>
79
+ </div>
80
+ <% end %>
81
+
82
+ <%= render Docs::ComponentPreviewComponent.new(
83
+ title: "Different Sizes",
84
+ code: navbar_sizes_code,
85
+ mobile_optimized: true
86
+ ) do %>
87
+ <div class="w-full space-y-4">
88
+ <div class="rounded-lg border border-border overflow-hidden">
89
+ <%= render M9sh::NavbarComponent.new(size: :sm, sticky: false) do |navbar| %>
90
+ <% navbar.with_brand do %>
91
+ <a href="#" class="font-bold">Small</a>
92
+ <% end %>
93
+ <% navbar.with_actions do %>
94
+ <%= render M9sh::ButtonComponent.new(size: :sm) do %>
95
+ Action
96
+ <% end %>
97
+ <% end %>
98
+ <% end %>
99
+ </div>
100
+
101
+ <div class="rounded-lg border border-border overflow-hidden">
102
+ <%= render M9sh::NavbarComponent.new(sticky: false) do |navbar| %>
103
+ <% navbar.with_brand do %>
104
+ <a href="#" class="font-bold text-xl">Default</a>
105
+ <% end %>
106
+ <% navbar.with_actions do %>
107
+ <%= render M9sh::ButtonComponent.new(size: :sm) do %>
108
+ Action
109
+ <% end %>
110
+ <% end %>
111
+ <% end %>
112
+ </div>
113
+
114
+ <div class="rounded-lg border border-border overflow-hidden">
115
+ <%= render M9sh::NavbarComponent.new(size: :lg, sticky: false) do |navbar| %>
116
+ <% navbar.with_brand do %>
117
+ <a href="#" class="font-bold text-2xl">Large</a>
118
+ <% end %>
119
+ <% navbar.with_actions do %>
120
+ <%= render M9sh::ButtonComponent.new do %>
121
+ Action
122
+ <% end %>
123
+ <% end %>
124
+ <% end %>
125
+ </div>
126
+ </div>
127
+ <% end %>
128
+
129
+ <%= render Docs::ComponentPreviewComponent.new(
130
+ title: "Blur Effect",
131
+ code: navbar_blur_code,
132
+ mobile_optimized: true
133
+ ) do %>
134
+ <div class="w-full bg-gradient-to-r from-green-50 to-blue-50 dark:from-green-950 dark:to-blue-950 p-8">
135
+ <%= render M9sh::NavbarComponent.new(blur: true, sticky: false) do |navbar| %>
136
+ <% navbar.with_brand do %>
137
+ <a href="#" class="font-bold text-xl">Blur Effect</a>
138
+ <% end %>
139
+
140
+ <% navbar.with_navigation do %>
141
+ <nav class="flex items-center gap-6">
142
+ <a href="#" class="text-sm font-medium">Home</a>
143
+ <a href="#" class="text-sm font-medium">Products</a>
144
+ </nav>
145
+ <% end %>
146
+
147
+ <% navbar.with_actions do %>
148
+ <%= render M9sh::ButtonComponent.new(variant: :outline, size: :sm) do %>
149
+ Contact
150
+ <% end %>
151
+ <% end %>
152
+ <% end %>
153
+ </div>
154
+ <% end %>
155
+
156
+ <%= render Docs::ComponentPreviewComponent.new(
157
+ title: "No Border",
158
+ code: navbar_no_border_code,
159
+ mobile_optimized: true
160
+ ) do %>
161
+ <div class="w-full">
162
+ <%= render M9sh::NavbarComponent.new(border: false, sticky: false) do |navbar| %>
163
+ <% navbar.with_brand do %>
164
+ <a href="#" class="font-bold text-xl">No Border</a>
165
+ <% end %>
166
+
167
+ <% navbar.with_navigation do %>
168
+ <nav class="flex items-center gap-4">
169
+ <a href="#" class="text-sm">Link 1</a>
170
+ <a href="#" class="text-sm">Link 2</a>
171
+ </nav>
172
+ <% end %>
173
+ <% end %>
174
+ </div>
175
+ <% end %>
176
+
177
+ <%= render Docs::ComponentPreviewComponent.new(
178
+ title: "Combined Options",
179
+ code: navbar_combined_options_code,
180
+ mobile_optimized: true
181
+ ) do %>
182
+ <div class="w-full bg-gradient-to-br from-orange-50 via-red-50 to-pink-50 dark:from-orange-950 dark:via-red-950 dark:to-pink-950 p-8">
183
+ <%= render M9sh::NavbarComponent.new(
184
+ sticky: false,
185
+ transparent: true,
186
+ container: false,
187
+ size: :lg,
188
+ border: false
189
+ ) do |navbar| %>
190
+ <% navbar.with_brand do %>
191
+ <a href="#" class="flex items-center space-x-2">
192
+ <span class="font-bold text-2xl">Custom</span>
193
+ </a>
194
+ <% end %>
195
+
196
+ <% navbar.with_navigation do %>
197
+ <nav class="flex items-center gap-6">
198
+ <a href="#" class="text-sm font-medium hover:text-primary transition-colors">Home</a>
199
+ <a href="#" class="text-sm font-medium hover:text-primary transition-colors">Features</a>
200
+ <a href="#" class="text-sm font-medium hover:text-primary transition-colors">Pricing</a>
201
+ <a href="#" class="text-sm font-medium hover:text-primary transition-colors">Contact</a>
202
+ </nav>
203
+ <% end %>
204
+
205
+ <% navbar.with_actions do %>
206
+ <%= render M9sh::ButtonComponent.new(variant: :ghost) do %>
207
+ Login
208
+ <% end %>
209
+ <% end %>
210
+
211
+ <% navbar.with_actions do %>
212
+ <%= render M9sh::ButtonComponent.new do %>
213
+ Get Started
214
+ <% end %>
215
+ <% end %>
216
+ <% end %>
217
+ </div>
218
+ <% end %>
219
+
220
+ <%= render Docs::ComponentPreviewComponent.new(
221
+ title: "Mobile Menu",
222
+ code: navbar_mobile_menu_code,
223
+ mobile_optimized: true
224
+ ) do %>
225
+ <div class="w-full">
226
+ <%= render M9sh::NavbarComponent.new(sticky: false) do |navbar| %>
227
+ <% navbar.with_brand do %>
228
+ <a href="#" class="font-bold text-xl">Brand</a>
229
+ <% end %>
230
+
231
+ <% navbar.with_navigation do %>
232
+ <nav class="flex items-center gap-6">
233
+ <a href="#" class="text-sm font-medium">Home</a>
234
+ <a href="#" class="text-sm font-medium">About</a>
235
+ <a href="#" class="text-sm font-medium">Services</a>
236
+ </nav>
237
+ <% end %>
238
+
239
+ <% navbar.with_actions do %>
240
+ <%= render M9sh::ButtonComponent.new(variant: :ghost, size: :sm) do %>
241
+ Login
242
+ <% end %>
243
+ <% end %>
244
+
245
+ <% navbar.with_actions do %>
246
+ <%= render M9sh::ButtonComponent.new(size: :sm) do %>
247
+ Sign Up
248
+ <% end %>
249
+ <% end %>
250
+
251
+ <% navbar.with_mobile_menu do %>
252
+ <%= render M9sh::DropdownMenuItemComponent.new(href: "#") do %>
253
+ Home
254
+ <% end %>
255
+ <%= render M9sh::DropdownMenuItemComponent.new(href: "#") do %>
256
+ About
257
+ <% end %>
258
+ <%= render M9sh::DropdownMenuItemComponent.new(href: "#") do %>
259
+ Services
260
+ <% end %>
261
+ <%= render M9sh::DropdownMenuSeparatorComponent.new %>
262
+ <%= render M9sh::DropdownMenuItemComponent.new(href: "#") do %>
263
+ Login
264
+ <% end %>
265
+ <%= render M9sh::DropdownMenuItemComponent.new(href: "#") do %>
266
+ Sign Up
267
+ <% end %>
268
+ <% end %>
269
+ <% end %>
270
+ </div>
271
+ <% end %>
272
+
273
+ <div class="mt-6">
274
+ <h3 class="text-lg font-semibold mb-3">More Examples</h3>
275
+ <p class="text-muted-foreground">
276
+ For complex real-world examples, check the layout files:
277
+ </p>
278
+ <ul class="list-disc list-inside text-sm text-muted-foreground space-y-1 ml-4 mt-2">
279
+ <li><code class="text-xs bg-muted px-1 py-0.5 rounded">app/views/layouts/application.html.erb</code> - Homepage navbar</li>
280
+ <li><code class="text-xs bg-muted px-1 py-0.5 rounded">app/views/layouts/docs.html.erb</code> - Documentation navbar (this page)</li>
281
+ <li><code class="text-xs bg-muted px-1 py-0.5 rounded">app/views/layouts/blocks.html.erb</code> - Blocks navbar</li>
282
+ </ul>
283
+ </div>
284
+ </div>
285
+ <% end %>
286
+
287
+ <% page.with_api do %>
288
+ <h3 class="text-lg font-semibold">NavbarComponent</h3>
289
+
290
+ <%= render Docs::PropTableComponent.new(
291
+ props: [
292
+ {
293
+ name: "sticky",
294
+ type: "Boolean",
295
+ default: "true",
296
+ description: "Whether the navbar should stick to the top of the viewport"
297
+ },
298
+ {
299
+ name: "transparent",
300
+ type: "Boolean",
301
+ default: "false",
302
+ description: "Whether to use a transparent backdrop-blur effect (glassmorphism)"
303
+ },
304
+ {
305
+ name: "container",
306
+ type: "Boolean",
307
+ default: "true",
308
+ description: "Whether to constrain content width with container class. Set to false for full width."
309
+ },
310
+ {
311
+ name: "size",
312
+ type: "Symbol",
313
+ default: ":default",
314
+ description: "Navbar height - :sm (48px), :default (64px), or :lg (80px)"
315
+ },
316
+ {
317
+ name: "border",
318
+ type: "Boolean",
319
+ default: "true",
320
+ description: "Whether to show bottom border"
321
+ },
322
+ {
323
+ name: "blur",
324
+ type: "Boolean",
325
+ default: "false",
326
+ description: "Add subtle blur effect without transparency"
327
+ }
328
+ ]
329
+ ) %>
330
+
331
+ <h3 class="text-lg font-semibold mt-6">Slots</h3>
332
+
333
+ <div class="mt-4 space-y-4">
334
+ <div>
335
+ <h4 class="text-base font-semibold">brand</h4>
336
+ <p class="text-sm text-muted-foreground mt-1">
337
+ Logo or brand section, typically on the left side. Use <code class="text-xs bg-muted px-1 py-0.5 rounded">with_brand</code> to define the brand content.
338
+ </p>
339
+ </div>
340
+
341
+ <div>
342
+ <h4 class="text-base font-semibold">navigation</h4>
343
+ <p class="text-sm text-muted-foreground mt-1">
344
+ Main navigation area, can contain links or a NavigationMenuComponent. Use <code class="text-xs bg-muted px-1 py-0.5 rounded">with_navigation</code> to define navigation content.
345
+ </p>
346
+ </div>
347
+
348
+ <div>
349
+ <h4 class="text-base font-semibold">actions</h4>
350
+ <p class="text-sm text-muted-foreground mt-1">
351
+ Action buttons on the right side (login, theme toggle, etc.). Use <code class="text-xs bg-muted px-1 py-0.5 rounded">with_actions</code> multiple times for multiple buttons.
352
+ </p>
353
+ </div>
354
+
355
+ <div>
356
+ <h4 class="text-base font-semibold">mobile_menu</h4>
357
+ <p class="text-sm text-muted-foreground mt-1">
358
+ Optional mobile menu content. Use <code class="text-xs bg-muted px-1 py-0.5 rounded">with_mobile_menu</code> to define mobile-specific navigation.
359
+ </p>
360
+ </div>
361
+ </div>
362
+
363
+ <div class="mt-6 space-y-2">
364
+ <h3 class="text-lg font-semibold">Usage Notes</h3>
365
+ <ul class="list-disc list-inside text-sm text-muted-foreground space-y-1">
366
+ <li>The navbar uses a container with responsive padding by default</li>
367
+ <li>The brand and navigation are grouped on the left</li>
368
+ <li>Actions appear on the right side</li>
369
+ <li>Three height options: 48px (sm), 64px (default), 80px (lg)</li>
370
+ <li>Navigation is automatically hidden on mobile (md breakpoint)</li>
371
+ <li>Desktop actions are automatically hidden on mobile (md breakpoint)</li>
372
+ <li>When <code class="text-xs bg-muted px-1 py-0.5 rounded">mobile_menu</code> is provided, a hamburger button appears on mobile</li>
373
+ <li>The hamburger button opens a dropdown menu below it with the mobile menu content</li>
374
+ <li>Use <code class="text-xs bg-muted px-1 py-0.5 rounded">DropdownMenuItemComponent</code> inside the mobile menu for menu items</li>
375
+ <li>Use <code class="text-xs bg-muted px-1 py-0.5 rounded">sticky: true</code> to make the navbar stick to the top</li>
376
+ <li>Use <code class="text-xs bg-muted px-1 py-0.5 rounded">transparent: true</code> for a glassmorphism effect</li>
377
+ <li>Use <code class="text-xs bg-muted px-1 py-0.5 rounded">blur: true</code> for a subtle blur without transparency</li>
378
+ <li>Use <code class="text-xs bg-muted px-1 py-0.5 rounded">container: false</code> to span the full viewport width</li>
379
+ <li>Use <code class="text-xs bg-muted px-1 py-0.5 rounded">border: false</code> to remove the bottom border</li>
380
+ <li>Combine with NavigationMenuComponent for dropdown menus</li>
381
+ <li>All options can be combined to create custom navbar styles</li>
382
+ </ul>
383
+ </div>
384
+
385
+ <div class="mt-6 space-y-2">
386
+ <h3 class="text-lg font-semibold">Related Components</h3>
387
+ <ul class="list-disc list-inside text-sm text-muted-foreground space-y-1">
388
+ <li><a href="/docs/navigation_menu" class="text-primary hover:underline">NavigationMenuComponent</a> - For dropdown navigation menus</li>
389
+ <li><a href="/docs/dropdown_menu" class="text-primary hover:underline">DropdownMenuComponent</a> - Automatically used for mobile menu dropdown</li>
390
+ <li><a href="/docs/button" class="text-primary hover:underline">ButtonComponent</a> - For action buttons</li>
391
+ </ul>
392
+ </div>
393
+ <% end %>
394
+ <% end %>
@@ -0,0 +1,226 @@
1
+ <%= render Docs::ComponentPageComponent.new(title: "Navigation Menu") do |page| %>
2
+ <% page.with_header(
3
+ name: "Navigation Menu",
4
+ description: "A collection of links for navigating websites."
5
+ ) %>
6
+
7
+ <% page.with_installation(component_name: "navigation_menu") %>
8
+
9
+ <% page.with_usage do %>
10
+ <%= render Docs::CodeBlockComponent.new(
11
+ code: navigation_menu_usage_code,
12
+ language: "erb"
13
+ ) %>
14
+ <% end %>
15
+
16
+ <% page.with_examples do %>
17
+ <!-- Default Example with Dropdowns -->
18
+ <% default_html = capture do %>
19
+ <div class="flex justify-center w-full py-8" style="min-height: 400px;">
20
+ <%= render M9sh::NavigationMenuComponent.new do |nav| %>
21
+ <% nav.with_item do |item| %>
22
+ <% item.with_trigger do %>
23
+ Getting started
24
+ <% end %>
25
+ <% item.with_menu_content do %>
26
+ <ul class="grid w-[400px] gap-3 p-4 md:w-[500px] md:grid-cols-[.75fr_1fr] lg:w-[600px]">
27
+ <li class="row-span-3">
28
+ <div class="flex h-full w-full select-none flex-col justify-end rounded-md bg-gradient-to-b from-muted/50 to-muted p-6 no-underline outline-none focus:shadow-md">
29
+ <div class="mb-2 mt-4 text-lg font-medium">
30
+ m9sh/ui
31
+ </div>
32
+ <p class="text-sm leading-tight text-muted-foreground">
33
+ Beautifully designed components built with ViewComponent and Tailwind CSS.
34
+ </p>
35
+ </div>
36
+ </li>
37
+ <li>
38
+ <a href="#" class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
39
+ <div class="text-sm font-medium leading-none">Introduction</div>
40
+ <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
41
+ Re-usable components built using ViewComponent and Tailwind CSS.
42
+ </p>
43
+ </a>
44
+ </li>
45
+ <li>
46
+ <a href="#" class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
47
+ <div class="text-sm font-medium leading-none">Installation</div>
48
+ <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
49
+ How to install dependencies and structure your app.
50
+ </p>
51
+ </a>
52
+ </li>
53
+ <li>
54
+ <a href="#" class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
55
+ <div class="text-sm font-medium leading-none">Typography</div>
56
+ <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
57
+ Styles for headings, paragraphs, lists...etc
58
+ </p>
59
+ </a>
60
+ </li>
61
+ </ul>
62
+ <% end %>
63
+ <% end %>
64
+
65
+ <% nav.with_item do |item| %>
66
+ <% item.with_trigger do %>
67
+ Components
68
+ <% end %>
69
+ <% item.with_menu_content do %>
70
+ <ul class="grid w-[600px] gap-3 p-6 md:grid-cols-2 lg:w-[800px]">
71
+ <li>
72
+ <a href="#" class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
73
+ <div class="text-sm font-medium leading-none">Alert Dialog</div>
74
+ <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
75
+ A modal dialog that interrupts the user with important content.
76
+ </p>
77
+ </a>
78
+ </li>
79
+ <li>
80
+ <a href="#" class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
81
+ <div class="text-sm font-medium leading-none">Hover Card</div>
82
+ <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
83
+ For sighted users to preview content available behind a link.
84
+ </p>
85
+ </a>
86
+ </li>
87
+ <li>
88
+ <a href="#" class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
89
+ <div class="text-sm font-medium leading-none">Progress</div>
90
+ <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
91
+ Displays an indicator showing the completion progress.
92
+ </p>
93
+ </a>
94
+ </li>
95
+ <li>
96
+ <a href="#" class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
97
+ <div class="text-sm font-medium leading-none">Scroll-area</div>
98
+ <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
99
+ Visually or semantically separates content.
100
+ </p>
101
+ </a>
102
+ </li>
103
+ <li>
104
+ <a href="#" class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
105
+ <div class="text-sm font-medium leading-none">Tabs</div>
106
+ <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
107
+ A set of layered sections of content.
108
+ </p>
109
+ </a>
110
+ </li>
111
+ <li>
112
+ <a href="#" class="block select-none space-y-1 rounded-md p-3 leading-none no-underline outline-none transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground">
113
+ <div class="text-sm font-medium leading-none">Tooltip</div>
114
+ <p class="line-clamp-2 text-sm leading-snug text-muted-foreground">
115
+ A popup that displays information related to an element.
116
+ </p>
117
+ </a>
118
+ </li>
119
+ </ul>
120
+ <% end %>
121
+ <% end %>
122
+ <% end %>
123
+ </div>
124
+ <% end %>
125
+
126
+ <%= render Docs::ComponentPreviewComponent.new(
127
+ title: "Default",
128
+ preview_content: default_html,
129
+ code: navigation_menu_default_code,
130
+ ai_command: navigation_menu_default_code
131
+ ) %>
132
+
133
+ <!-- Simple Links Example -->
134
+ <% links_html = capture do %>
135
+ <div class="flex justify-center w-full py-8">
136
+ <%= render M9sh::NavigationMenuComponent.new do |nav| %>
137
+ <% nav.with_item do |item| %>
138
+ <% item.with_link(href: "#docs") do %>
139
+ Documentation
140
+ <% end %>
141
+ <% end %>
142
+
143
+ <% nav.with_item do |item| %>
144
+ <% item.with_link(href: "#components") do %>
145
+ Components
146
+ <% end %>
147
+ <% end %>
148
+
149
+ <% nav.with_item do |item| %>
150
+ <% item.with_link(href: "#examples") do %>
151
+ Examples
152
+ <% end %>
153
+ <% end %>
154
+ <% end %>
155
+ </div>
156
+ <% end %>
157
+
158
+ <%= render Docs::ComponentPreviewComponent.new(
159
+ title: "Simple Links",
160
+ preview_content: links_html,
161
+ code: navigation_menu_simple_links_code,
162
+ ai_command: navigation_menu_simple_links_code
163
+ ) %>
164
+ <% end %>
165
+
166
+ <% page.with_api do %>
167
+ <h3 class="text-lg font-semibold mb-4">NavigationMenuComponent</h3>
168
+ <%= render Docs::PropTableComponent.new(
169
+ props: [
170
+ {
171
+ name: "items",
172
+ type: "renders_many",
173
+ default: "[]",
174
+ description: "Collection of navigation menu items (ItemComponent instances)"
175
+ }
176
+ ]
177
+ ) %>
178
+
179
+ <h3 class="text-lg font-semibold mb-4 mt-8">ItemComponent</h3>
180
+ <%= render Docs::PropTableComponent.new(
181
+ props: [
182
+ {
183
+ name: "trigger",
184
+ type: "renders_one",
185
+ default: "nil",
186
+ description: "Button trigger for dropdown menu with text/block content"
187
+ },
188
+ {
189
+ name: "menu_content",
190
+ type: "renders_one",
191
+ default: "nil",
192
+ description: "Dropdown menu content panel"
193
+ },
194
+ {
195
+ name: "link",
196
+ type: "renders_one",
197
+ default: "nil",
198
+ description: "Simple navigation link (alternative to trigger+menu_content)"
199
+ }
200
+ ]
201
+ ) %>
202
+
203
+ <div class="mt-6 space-y-3 text-sm">
204
+ <h3 class="text-lg font-semibold">Usage Notes</h3>
205
+ <ul class="list-disc list-inside space-y-2 text-muted-foreground">
206
+ <li>Use <code class="text-xs bg-muted px-1 py-0.5 rounded">trigger</code> and <code class="text-xs bg-muted px-1 py-0.5 rounded">menu_content</code> together for dropdown menus</li>
207
+ <li>Use <code class="text-xs bg-muted px-1 py-0.5 rounded">link</code> alone for simple navigation links</li>
208
+ <li>The component uses Stimulus.js for interactive dropdown behavior</li>
209
+ <li>Clicking outside an open dropdown will automatically close it</li>
210
+ <li>The dropdown content includes smooth animations for opening/closing</li>
211
+ <li>The trigger button shows a chevron icon that rotates when the menu opens</li>
212
+ </ul>
213
+ </div>
214
+
215
+ <div class="mt-6 space-y-3 text-sm">
216
+ <h3 class="text-lg font-semibold">Accessibility</h3>
217
+ <ul class="list-disc list-inside space-y-2 text-muted-foreground">
218
+ <li>Uses semantic <code class="text-xs bg-muted px-1 py-0.5 rounded">&lt;nav&gt;</code> element</li>
219
+ <li>Trigger buttons have proper <code class="text-xs bg-muted px-1 py-0.5 rounded">type="button"</code> attribute</li>
220
+ <li>Chevron icon has <code class="text-xs bg-muted px-1 py-0.5 rounded">aria-hidden="true"</code> to prevent screen reader announcement</li>
221
+ <li>Focus states are styled with <code class="text-xs bg-muted px-1 py-0.5 rounded">focus:outline-none</code> and custom focus styling</li>
222
+ <li>Links use proper <code class="text-xs bg-muted px-1 py-0.5 rounded">&lt;a&gt;</code> tags with href attributes</li>
223
+ </ul>
224
+ </div>
225
+ <% end %>
226
+ <% end %>