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.
- checksums.yaml +4 -4
- data/.idea/hotcdn.iml +30 -0
- data/.mise.toml +2 -2
- data/app/assets/config/manifest.js +4 -0
- data/app/assets/images/icons/activity.svg +3 -0
- data/app/assets/images/icons/bell.svg +4 -0
- data/app/assets/images/icons/book.svg +4 -0
- data/app/assets/images/icons/chevron-down.svg +3 -0
- data/app/assets/images/icons/chevron-left.svg +3 -0
- data/app/assets/images/icons/chevron-right.svg +3 -0
- data/app/assets/images/icons/credit-card.svg +4 -0
- data/app/assets/images/icons/dollar-sign.svg +3 -0
- data/app/assets/images/icons/edit.svg +4 -0
- data/app/assets/images/icons/github.svg +3 -0
- data/app/assets/images/icons/home.svg +4 -0
- data/app/assets/images/icons/info.svg +5 -0
- data/app/assets/images/icons/layout.svg +6 -0
- data/app/assets/images/icons/logout.svg +5 -0
- data/app/assets/images/icons/menu.svg +5 -0
- data/app/assets/images/icons/moon.svg +3 -0
- data/app/assets/images/icons/paintbrush.svg +6 -0
- data/app/assets/images/icons/search.svg +4 -0
- data/app/assets/images/icons/settings.svg +4 -0
- data/app/assets/images/icons/sun.svg +11 -0
- data/app/assets/images/icons/user.svg +4 -0
- data/app/assets/images/icons/users.svg +5 -0
- data/app/assets/stylesheets/tailwind.css +1180 -0
- data/app/components/backdrop_component.rb +103 -0
- data/app/components/docs/code_block_component.rb +56 -0
- data/app/components/docs/component_api_component.rb +16 -0
- data/app/components/docs/component_examples_component.rb +16 -0
- data/app/components/docs/component_header_component.html.erb +8 -0
- data/app/components/docs/component_header_component.rb +14 -0
- data/app/components/docs/component_installation_component.html.erb +15 -0
- data/app/components/docs/component_installation_component.rb +13 -0
- data/app/components/docs/component_page_component.html.erb +9 -0
- data/app/components/docs/component_page_component.rb +19 -0
- data/app/components/docs/component_preview_component.rb +318 -0
- data/app/components/docs/component_usage_component.rb +18 -0
- data/app/components/docs/prop_table_component.rb +64 -0
- data/app/controllers/application_controller.rb +3 -0
- data/app/controllers/blocks_controller.rb +51 -0
- data/app/controllers/docs_controller.rb +162 -0
- data/app/controllers/showcase_controller.rb +42 -0
- data/app/helpers/blocks_helper.rb +343 -0
- data/app/helpers/docs_helper.rb +3807 -0
- data/app/helpers/m9sh/toast_helper.rb +46 -0
- data/app/helpers/m9sh_helper.rb +343 -0
- data/app/javascript/application.js +3 -0
- data/app/javascript/controllers/application.js +9 -0
- data/app/javascript/controllers/backdrop_controller.js +137 -0
- data/app/javascript/controllers/color_customizer_controller.js +569 -0
- data/app/javascript/controllers/color_theme_controller.js +120 -0
- data/app/javascript/controllers/docs/component_preview_controller.js +149 -0
- data/app/javascript/controllers/docs/copy_button_controller.js +20 -0
- data/app/javascript/controllers/index.js +6 -0
- data/app/javascript/controllers/theme_controller.js +23 -0
- data/app/views/blocks/_sidebar.html.erb +31 -0
- data/app/views/blocks/_toc.html.erb +29 -0
- data/app/views/blocks/examples/dashboard-01.html.erb +180 -0
- data/app/views/blocks/examples/dashboard-02.html.erb +190 -0
- data/app/views/blocks/examples/dashboard-03.html.erb +210 -0
- data/app/views/blocks/examples/settings-01.html.erb +220 -0
- data/app/views/blocks/examples/settings-02.html.erb +231 -0
- data/app/views/blocks/examples/settings-03.html.erb +340 -0
- data/app/views/blocks/index.html.erb +65 -0
- data/app/views/docs/_sidebar.html.erb +47 -0
- data/app/views/docs/_toc.html.erb +19 -0
- data/app/views/docs/about.html.erb +68 -0
- data/app/views/docs/components/accordion.html.erb +196 -0
- data/app/views/docs/components/alert.html.erb +272 -0
- data/app/views/docs/components/alert_dialog.html.erb +232 -0
- data/app/views/docs/components/avatar.html.erb +207 -0
- data/app/views/docs/components/badge.html.erb +145 -0
- data/app/views/docs/components/breadcrumb.html.erb +264 -0
- data/app/views/docs/components/button.html.erb +229 -0
- data/app/views/docs/components/card.html.erb +378 -0
- data/app/views/docs/components/checkbox.html.erb +212 -0
- data/app/views/docs/components/collapsible.html.erb +252 -0
- data/app/views/docs/components/dialog.html.erb +323 -0
- data/app/views/docs/components/dropdown_menu.html.erb +289 -0
- data/app/views/docs/components/hover_card.html.erb +220 -0
- data/app/views/docs/components/input.html.erb +254 -0
- data/app/views/docs/components/label.html.erb +128 -0
- data/app/views/docs/components/main.html.erb +352 -0
- data/app/views/docs/components/navbar.html.erb +394 -0
- data/app/views/docs/components/navigation_menu.html.erb +226 -0
- data/app/views/docs/components/popover.html.erb +267 -0
- data/app/views/docs/components/progress.html.erb +107 -0
- data/app/views/docs/components/radio_group.html.erb +209 -0
- data/app/views/docs/components/select.html.erb +260 -0
- data/app/views/docs/components/separator.html.erb +162 -0
- data/app/views/docs/components/sheet.html.erb +270 -0
- data/app/views/docs/components/sidebar.html.erb +597 -0
- data/app/views/docs/components/skeleton.html.erb +150 -0
- data/app/views/docs/components/slider.html.erb +218 -0
- data/app/views/docs/components/spinner.html.erb +132 -0
- data/app/views/docs/components/switch.html.erb +148 -0
- data/app/views/docs/components/table.html.erb +259 -0
- data/app/views/docs/components/tabs.html.erb +225 -0
- data/app/views/docs/components/textarea.html.erb +239 -0
- data/app/views/docs/components/theme_toggle.html.erb +135 -0
- data/app/views/docs/components/toast.html.erb +205 -0
- data/app/views/docs/components/toaster.html.erb +227 -0
- data/app/views/docs/components/toggle.html.erb +154 -0
- data/app/views/docs/components/tooltip.html.erb +216 -0
- data/app/views/docs/components/typography.html.erb +180 -0
- data/app/views/docs/index.html.erb +143 -0
- data/app/views/docs/installation.html.erb +155 -0
- data/app/views/docs/simple_test.html.erb +13 -0
- data/app/views/docs/test_accordion.html.erb +14 -0
- data/app/views/docs/usage.html.erb +272 -0
- data/app/views/layouts/application.html.erb +107 -0
- data/app/views/layouts/backdrop.html.erb +77 -0
- data/app/views/shared/_app_navbar.html.erb +240 -0
- data/app/views/shared/_navbar.html.erb +69 -0
- data/app/views/showcase/v2/_components_grid.html.erb +38 -0
- data/app/views/showcase/v2/_features.html.erb +59 -0
- data/app/views/showcase/v2/_forms.html.erb +195 -0
- data/app/views/showcase/v2/_hero.html.erb +55 -0
- data/app/views/showcase/v2/_metrics.html.erb +107 -0
- data/app/views/showcase/v2.html.erb +18 -0
- data/lib/m9sh/version.rb +1 -1
- data/m9sh.gemspec +1 -1
- metadata +120 -1
@@ -0,0 +1,289 @@
|
|
1
|
+
<%= render Docs::ComponentPageComponent.new(title: "Dropdown Menu") do |page| %>
|
2
|
+
<% page.with_header(
|
3
|
+
name: "Dropdown Menu",
|
4
|
+
description: "Displays a menu to the user with a list of actions or options."
|
5
|
+
) %>
|
6
|
+
|
7
|
+
<% page.with_installation(component_name: "dropdown_menu") %>
|
8
|
+
|
9
|
+
<% page.with_usage do %>
|
10
|
+
<%= render Docs::CodeBlockComponent.new(
|
11
|
+
code: dropdown_menu_usage_code,
|
12
|
+
language: "erb"
|
13
|
+
) %>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<% page.with_examples do %>
|
17
|
+
<!-- Default Example -->
|
18
|
+
<% default_html = capture do %>
|
19
|
+
<div class="flex justify-center items-center p-8">
|
20
|
+
<%= render M9sh::DropdownMenuComponent.new do %>
|
21
|
+
<%= render M9sh::DropdownMenuTriggerComponent.new(class: "px-4 py-2 rounded-md border border-border bg-background hover:bg-muted transition-colors") do %>
|
22
|
+
Open
|
23
|
+
<% end %>
|
24
|
+
<%= render M9sh::DropdownMenuContentComponent.new do %>
|
25
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
26
|
+
Profile
|
27
|
+
<% end %>
|
28
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
29
|
+
Settings
|
30
|
+
<% end %>
|
31
|
+
<%= render M9sh::DropdownMenuSeparatorComponent.new %>
|
32
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
33
|
+
Logout
|
34
|
+
<% end %>
|
35
|
+
<% end %>
|
36
|
+
<% end %>
|
37
|
+
</div>
|
38
|
+
<% end %>
|
39
|
+
|
40
|
+
<%= render Docs::ComponentPreviewComponent.new(
|
41
|
+
title: "Default",
|
42
|
+
preview_content: default_html,
|
43
|
+
code: dropdown_menu_default_code,
|
44
|
+
ai_command: dropdown_menu_default_code
|
45
|
+
) %>
|
46
|
+
|
47
|
+
<!-- With Icons Example -->
|
48
|
+
<% icons_html = capture do %>
|
49
|
+
<div class="flex justify-center items-center p-8">
|
50
|
+
<%= render M9sh::DropdownMenuComponent.new do %>
|
51
|
+
<%= render M9sh::DropdownMenuTriggerComponent.new(class: "px-4 py-2 rounded-md border border-border bg-background hover:bg-muted transition-colors") do %>
|
52
|
+
Open Menu
|
53
|
+
<% end %>
|
54
|
+
<%= render M9sh::DropdownMenuContentComponent.new do %>
|
55
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
56
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="mr-2">
|
57
|
+
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2"/>
|
58
|
+
<circle cx="12" cy="7" r="4"/>
|
59
|
+
</svg>
|
60
|
+
Profile
|
61
|
+
<% end %>
|
62
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
63
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="mr-2">
|
64
|
+
<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"/>
|
65
|
+
<circle cx="12" cy="12" r="3"/>
|
66
|
+
</svg>
|
67
|
+
Settings
|
68
|
+
<% end %>
|
69
|
+
<%= render M9sh::DropdownMenuSeparatorComponent.new %>
|
70
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
71
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="mr-2">
|
72
|
+
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/>
|
73
|
+
<polyline points="16 17 21 12 16 7"/>
|
74
|
+
<line x1="21" y1="12" x2="9" y2="12"/>
|
75
|
+
</svg>
|
76
|
+
Logout
|
77
|
+
<% end %>
|
78
|
+
<% end %>
|
79
|
+
<% end %>
|
80
|
+
</div>
|
81
|
+
<% end %>
|
82
|
+
|
83
|
+
<%= render Docs::ComponentPreviewComponent.new(
|
84
|
+
title: "With Icons",
|
85
|
+
preview_content: icons_html,
|
86
|
+
code: dropdown_menu_with_icons_code,
|
87
|
+
ai_command: dropdown_menu_with_icons_code
|
88
|
+
) %>
|
89
|
+
|
90
|
+
<!-- With Separators Example -->
|
91
|
+
<% separators_html = capture do %>
|
92
|
+
<div class="flex justify-center items-center p-8">
|
93
|
+
<%= render M9sh::DropdownMenuComponent.new do %>
|
94
|
+
<%= render M9sh::DropdownMenuTriggerComponent.new(class: "px-4 py-2 rounded-md border border-border bg-background hover:bg-muted transition-colors") do %>
|
95
|
+
Options
|
96
|
+
<% end %>
|
97
|
+
<%= render M9sh::DropdownMenuContentComponent.new do %>
|
98
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
99
|
+
New Tab
|
100
|
+
<% end %>
|
101
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
102
|
+
New Window
|
103
|
+
<% end %>
|
104
|
+
<%= render M9sh::DropdownMenuSeparatorComponent.new %>
|
105
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
106
|
+
History
|
107
|
+
<% end %>
|
108
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
109
|
+
Downloads
|
110
|
+
<% end %>
|
111
|
+
<%= render M9sh::DropdownMenuSeparatorComponent.new %>
|
112
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
113
|
+
Settings
|
114
|
+
<% end %>
|
115
|
+
<% end %>
|
116
|
+
<% end %>
|
117
|
+
</div>
|
118
|
+
<% end %>
|
119
|
+
|
120
|
+
<%= render Docs::ComponentPreviewComponent.new(
|
121
|
+
title: "With Separators",
|
122
|
+
preview_content: separators_html,
|
123
|
+
code: dropdown_menu_with_separators_code,
|
124
|
+
ai_command: dropdown_menu_with_separators_code
|
125
|
+
) %>
|
126
|
+
|
127
|
+
<!-- Alignment Example -->
|
128
|
+
<% alignment_html = capture do %>
|
129
|
+
<div class="flex justify-center items-center gap-4 p-8">
|
130
|
+
<%= render M9sh::DropdownMenuComponent.new(align: "start") do %>
|
131
|
+
<%= render M9sh::DropdownMenuTriggerComponent.new(class: "px-4 py-2 rounded-md border border-border bg-background hover:bg-muted transition-colors text-sm") do %>
|
132
|
+
Align Start
|
133
|
+
<% end %>
|
134
|
+
<%= render M9sh::DropdownMenuContentComponent.new do %>
|
135
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
136
|
+
Item 1
|
137
|
+
<% end %>
|
138
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
139
|
+
Item 2
|
140
|
+
<% end %>
|
141
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
142
|
+
Item 3
|
143
|
+
<% end %>
|
144
|
+
<% end %>
|
145
|
+
<% end %>
|
146
|
+
|
147
|
+
<%= render M9sh::DropdownMenuComponent.new(align: "end") do %>
|
148
|
+
<%= render M9sh::DropdownMenuTriggerComponent.new(class: "px-4 py-2 rounded-md border border-border bg-background hover:bg-muted transition-colors text-sm") do %>
|
149
|
+
Align End
|
150
|
+
<% end %>
|
151
|
+
<%= render M9sh::DropdownMenuContentComponent.new do %>
|
152
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
153
|
+
Item 1
|
154
|
+
<% end %>
|
155
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
156
|
+
Item 2
|
157
|
+
<% end %>
|
158
|
+
<%= render M9sh::DropdownMenuItemComponent.new do %>
|
159
|
+
Item 3
|
160
|
+
<% end %>
|
161
|
+
<% end %>
|
162
|
+
<% end %>
|
163
|
+
</div>
|
164
|
+
<% end %>
|
165
|
+
|
166
|
+
<%= render Docs::ComponentPreviewComponent.new(
|
167
|
+
title: "Alignment",
|
168
|
+
preview_content: alignment_html,
|
169
|
+
code: dropdown_menu_alignment_code,
|
170
|
+
ai_command: dropdown_menu_alignment_code
|
171
|
+
) %>
|
172
|
+
<% end %>
|
173
|
+
|
174
|
+
<% page.with_api do %>
|
175
|
+
<h3 class="text-lg font-semibold">DropdownMenuComponent</h3>
|
176
|
+
|
177
|
+
<%= render Docs::PropTableComponent.new(
|
178
|
+
props: [
|
179
|
+
{
|
180
|
+
name: "align",
|
181
|
+
type: "String",
|
182
|
+
default: '"end"',
|
183
|
+
description: "The alignment of the menu relative to the trigger. Options: 'start', 'end'"
|
184
|
+
},
|
185
|
+
{
|
186
|
+
name: "side",
|
187
|
+
type: "String",
|
188
|
+
default: '"bottom"',
|
189
|
+
description: "The preferred side of the trigger to render against. Options: 'top', 'bottom'"
|
190
|
+
}
|
191
|
+
]
|
192
|
+
) %>
|
193
|
+
|
194
|
+
<h3 class="text-lg font-semibold mt-6">DropdownMenuTriggerComponent</h3>
|
195
|
+
|
196
|
+
<p class="text-sm text-muted-foreground">
|
197
|
+
The button that toggles the dropdown menu. Accepts all standard button attributes and can be styled with additional classes.
|
198
|
+
</p>
|
199
|
+
|
200
|
+
<h3 class="text-lg font-semibold mt-6">DropdownMenuContentComponent</h3>
|
201
|
+
|
202
|
+
<p class="text-sm text-muted-foreground">
|
203
|
+
The container for the dropdown menu items. Appears as a popover with shadow and border styling. Automatically positioned based on the parent component's align and side settings.
|
204
|
+
</p>
|
205
|
+
|
206
|
+
<h3 class="text-lg font-semibold mt-6">DropdownMenuItemComponent</h3>
|
207
|
+
|
208
|
+
<%= render Docs::PropTableComponent.new(
|
209
|
+
props: [
|
210
|
+
{
|
211
|
+
name: "href",
|
212
|
+
type: "String",
|
213
|
+
default: "nil",
|
214
|
+
description: "If provided, renders the item as a link instead of a button"
|
215
|
+
},
|
216
|
+
{
|
217
|
+
name: "method",
|
218
|
+
type: "String",
|
219
|
+
default: "nil",
|
220
|
+
description: "HTTP method for the link (e.g., :delete, :post)"
|
221
|
+
}
|
222
|
+
]
|
223
|
+
) %>
|
224
|
+
|
225
|
+
<h3 class="text-lg font-semibold mt-6">DropdownMenuSeparatorComponent</h3>
|
226
|
+
|
227
|
+
<p class="text-sm text-muted-foreground">
|
228
|
+
A visual separator to group related menu items. Renders as a thin horizontal line.
|
229
|
+
</p>
|
230
|
+
|
231
|
+
<div class="mt-6 space-y-2">
|
232
|
+
<h3 class="text-lg font-semibold">Accessibility</h3>
|
233
|
+
|
234
|
+
<div class="space-y-3 text-sm">
|
235
|
+
<p>
|
236
|
+
The Dropdown Menu component is built with keyboard navigation and screen reader support:
|
237
|
+
</p>
|
238
|
+
|
239
|
+
<ul class="list-disc list-inside space-y-2 text-muted-foreground">
|
240
|
+
<li>
|
241
|
+
Toggle the menu by clicking the trigger button
|
242
|
+
</li>
|
243
|
+
<li>
|
244
|
+
The menu automatically closes when clicking outside or selecting an item
|
245
|
+
</li>
|
246
|
+
<li>
|
247
|
+
Menu items can be either buttons or links, supporting different interaction patterns
|
248
|
+
</li>
|
249
|
+
<li>
|
250
|
+
Items are styled with hover and focus states for clear visual feedback
|
251
|
+
</li>
|
252
|
+
<li>
|
253
|
+
Smooth transitions provide polished enter and exit animations
|
254
|
+
</li>
|
255
|
+
<li>
|
256
|
+
The menu is positioned absolutely and uses z-index to appear above other content
|
257
|
+
</li>
|
258
|
+
</ul>
|
259
|
+
</div>
|
260
|
+
</div>
|
261
|
+
|
262
|
+
<div class="mt-6 space-y-2">
|
263
|
+
<h3 class="text-lg font-semibold">Notes</h3>
|
264
|
+
<ul class="list-disc list-inside text-sm text-muted-foreground space-y-1">
|
265
|
+
<li>
|
266
|
+
Use <code class="text-xs bg-muted px-1 py-0.5 rounded">DropdownMenuItemComponent</code> with the <code class="text-xs bg-muted px-1 py-0.5 rounded">href</code> parameter for navigation
|
267
|
+
</li>
|
268
|
+
<li>
|
269
|
+
Use <code class="text-xs bg-muted px-1 py-0.5 rounded">DropdownMenuItemComponent</code> without <code class="text-xs bg-muted px-1 py-0.5 rounded">href</code> for actions that trigger JavaScript or form submissions
|
270
|
+
</li>
|
271
|
+
<li>
|
272
|
+
Separators help organize menu items into logical groups
|
273
|
+
</li>
|
274
|
+
<li>
|
275
|
+
Icons can be added to menu items by including SVG elements in the item content
|
276
|
+
</li>
|
277
|
+
<li>
|
278
|
+
The menu automatically closes when an item is clicked
|
279
|
+
</li>
|
280
|
+
<li>
|
281
|
+
Use the <code class="text-xs bg-muted px-1 py-0.5 rounded">align</code> parameter to control whether the menu aligns to the start or end of the trigger
|
282
|
+
</li>
|
283
|
+
<li>
|
284
|
+
Multiple dropdown menus can exist on the same page independently
|
285
|
+
</li>
|
286
|
+
</ul>
|
287
|
+
</div>
|
288
|
+
<% end %>
|
289
|
+
<% end %>
|
@@ -0,0 +1,220 @@
|
|
1
|
+
<%= render Docs::ComponentPageComponent.new(title: "Hover Card") do |page| %>
|
2
|
+
<% page.with_header(
|
3
|
+
name: "Hover Card",
|
4
|
+
description: "For sighted users to preview content available behind a link in a richer format."
|
5
|
+
) %>
|
6
|
+
|
7
|
+
<% page.with_installation(component_name: "hover_card") %>
|
8
|
+
|
9
|
+
<% page.with_usage do %>
|
10
|
+
<%= render Docs::CodeBlockComponent.new(
|
11
|
+
code: hover_card_usage_code,
|
12
|
+
language: "erb"
|
13
|
+
) %>
|
14
|
+
<% end %>
|
15
|
+
|
16
|
+
<% page.with_examples do %>
|
17
|
+
<!-- Default Example -->
|
18
|
+
<% default_html = capture do %>
|
19
|
+
<div class="flex justify-center items-center p-8">
|
20
|
+
<%= render M9sh::HoverCardComponent.new do |card| %>
|
21
|
+
<% card.with_trigger do %>
|
22
|
+
<span class="underline cursor-pointer text-sm font-medium">@username</span>
|
23
|
+
<% end %>
|
24
|
+
<% card.with_hover_content do %>
|
25
|
+
<div class="space-y-2">
|
26
|
+
<h4 class="text-sm font-semibold">@username</h4>
|
27
|
+
<p class="text-sm text-muted-foreground">
|
28
|
+
The hover card component is a rich preview that appears when hovering over a trigger element.
|
29
|
+
</p>
|
30
|
+
</div>
|
31
|
+
<% end %>
|
32
|
+
<% end %>
|
33
|
+
</div>
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
<%= render Docs::ComponentPreviewComponent.new(
|
37
|
+
title: "Default",
|
38
|
+
preview_content: default_html,
|
39
|
+
code: hover_card_default_code,
|
40
|
+
ai_command: hover_card_default_code
|
41
|
+
) %>
|
42
|
+
|
43
|
+
<!-- With Avatar Example -->
|
44
|
+
<% avatar_html = capture do %>
|
45
|
+
<div class="flex justify-center items-center p-8">
|
46
|
+
<%= render M9sh::HoverCardComponent.new do |card| %>
|
47
|
+
<% card.with_trigger do %>
|
48
|
+
<span class="underline cursor-pointer text-sm font-medium">@nextjs</span>
|
49
|
+
<% end %>
|
50
|
+
<% card.with_hover_content do %>
|
51
|
+
<div class="flex gap-4">
|
52
|
+
<%= render M9sh::AvatarComponent.new(
|
53
|
+
src: "https://github.com/vercel.png",
|
54
|
+
fallback: "VC",
|
55
|
+
size: :md
|
56
|
+
) %>
|
57
|
+
<div class="space-y-1">
|
58
|
+
<h4 class="text-sm font-semibold">@nextjs</h4>
|
59
|
+
<p class="text-sm text-muted-foreground">
|
60
|
+
The React Framework - created and maintained by @vercel.
|
61
|
+
</p>
|
62
|
+
<div class="flex items-center pt-2">
|
63
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="mr-1">
|
64
|
+
<rect x="2" y="7" width="20" height="14" rx="2" ry="2"/>
|
65
|
+
<path d="M16 21V5a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16"/>
|
66
|
+
</svg>
|
67
|
+
<span class="text-xs text-muted-foreground">Joined December 2021</span>
|
68
|
+
</div>
|
69
|
+
</div>
|
70
|
+
</div>
|
71
|
+
<% end %>
|
72
|
+
<% end %>
|
73
|
+
</div>
|
74
|
+
<% end %>
|
75
|
+
|
76
|
+
<%= render Docs::ComponentPreviewComponent.new(
|
77
|
+
title: "With Avatar and Content",
|
78
|
+
preview_content: avatar_html,
|
79
|
+
code: hover_card_with_avatar_code,
|
80
|
+
ai_command: hover_card_with_avatar_code
|
81
|
+
) %>
|
82
|
+
|
83
|
+
<!-- Complex Content Example -->
|
84
|
+
<% complex_html = capture do %>
|
85
|
+
<div class="flex justify-center items-center p-8">
|
86
|
+
<%= render M9sh::HoverCardComponent.new(open_delay: 300, close_delay: 400) do |card| %>
|
87
|
+
<% card.with_trigger do %>
|
88
|
+
<span class="underline cursor-pointer text-sm font-medium">View Details</span>
|
89
|
+
<% end %>
|
90
|
+
<% card.with_hover_content do %>
|
91
|
+
<div class="space-y-3">
|
92
|
+
<div>
|
93
|
+
<h4 class="text-sm font-semibold mb-1">Product Information</h4>
|
94
|
+
<p class="text-xs text-muted-foreground">
|
95
|
+
Hover over elements to see detailed information without navigating away from the current page.
|
96
|
+
</p>
|
97
|
+
</div>
|
98
|
+
<div class="border-t pt-3 space-y-2">
|
99
|
+
<div class="flex justify-between text-xs">
|
100
|
+
<span class="text-muted-foreground">Price:</span>
|
101
|
+
<span class="font-medium">$29.99</span>
|
102
|
+
</div>
|
103
|
+
<div class="flex justify-between text-xs">
|
104
|
+
<span class="text-muted-foreground">In Stock:</span>
|
105
|
+
<span class="font-medium text-green-600">Yes</span>
|
106
|
+
</div>
|
107
|
+
<div class="flex justify-between text-xs">
|
108
|
+
<span class="text-muted-foreground">Rating:</span>
|
109
|
+
<span class="font-medium">4.5/5</span>
|
110
|
+
</div>
|
111
|
+
</div>
|
112
|
+
</div>
|
113
|
+
<% end %>
|
114
|
+
<% end %>
|
115
|
+
</div>
|
116
|
+
<% end %>
|
117
|
+
|
118
|
+
<%= render Docs::ComponentPreviewComponent.new(
|
119
|
+
title: "Complex Content",
|
120
|
+
preview_content: complex_html,
|
121
|
+
code: hover_card_complex_code,
|
122
|
+
ai_command: hover_card_complex_code
|
123
|
+
) %>
|
124
|
+
<% end %>
|
125
|
+
|
126
|
+
<% page.with_api do %>
|
127
|
+
<h3 class="text-lg font-semibold">HoverCardComponent</h3>
|
128
|
+
|
129
|
+
<%= render Docs::PropTableComponent.new(
|
130
|
+
props: [
|
131
|
+
{
|
132
|
+
name: "open_delay",
|
133
|
+
type: "Number",
|
134
|
+
default: "200",
|
135
|
+
description: "The duration in milliseconds from when the mouse enters the trigger until the hover card opens"
|
136
|
+
},
|
137
|
+
{
|
138
|
+
name: "close_delay",
|
139
|
+
type: "Number",
|
140
|
+
default: "300",
|
141
|
+
description: "The duration in milliseconds from when the mouse leaves the trigger or content until the hover card closes"
|
142
|
+
}
|
143
|
+
]
|
144
|
+
) %>
|
145
|
+
|
146
|
+
<h3 class="text-lg font-semibold mt-6">Slots</h3>
|
147
|
+
|
148
|
+
<%= render Docs::PropTableComponent.new(
|
149
|
+
props: [
|
150
|
+
{
|
151
|
+
name: "trigger",
|
152
|
+
type: "Slot",
|
153
|
+
default: "-",
|
154
|
+
description: "The element that triggers the hover card. Typically a link or interactive element."
|
155
|
+
},
|
156
|
+
{
|
157
|
+
name: "hover_content",
|
158
|
+
type: "Slot",
|
159
|
+
default: "-",
|
160
|
+
description: "The rich content to display in the hover card"
|
161
|
+
}
|
162
|
+
]
|
163
|
+
) %>
|
164
|
+
|
165
|
+
<div class="mt-6 space-y-4">
|
166
|
+
<h3 class="text-lg font-semibold">Accessibility</h3>
|
167
|
+
|
168
|
+
<div class="space-y-3 text-sm">
|
169
|
+
<p>
|
170
|
+
The Hover Card component is designed for sighted users and provides enhanced preview functionality:
|
171
|
+
</p>
|
172
|
+
|
173
|
+
<ul class="list-disc list-inside space-y-2 text-muted-foreground">
|
174
|
+
<li>
|
175
|
+
The hover card appears after a configurable delay when hovering over the trigger element
|
176
|
+
</li>
|
177
|
+
<li>
|
178
|
+
Users can move their mouse into the hover card content, which prevents it from closing
|
179
|
+
</li>
|
180
|
+
<li>
|
181
|
+
The card automatically closes when the mouse leaves both the trigger and content areas
|
182
|
+
</li>
|
183
|
+
<li>
|
184
|
+
Smooth animations with fade and zoom effects provide polished transitions
|
185
|
+
</li>
|
186
|
+
<li>
|
187
|
+
The content is positioned in a fixed-width container (w-64) by default with a popover style
|
188
|
+
</li>
|
189
|
+
</ul>
|
190
|
+
</div>
|
191
|
+
</div>
|
192
|
+
|
193
|
+
<div class="mt-6 space-y-4">
|
194
|
+
<h3 class="text-lg font-semibold">Notes</h3>
|
195
|
+
|
196
|
+
<div class="space-y-3 text-sm">
|
197
|
+
<ul class="list-disc list-inside space-y-2 text-muted-foreground">
|
198
|
+
<li>
|
199
|
+
Hover cards are ideal for user profiles, product previews, and supplementary information
|
200
|
+
</li>
|
201
|
+
<li>
|
202
|
+
Unlike tooltips, hover cards can contain interactive elements and richer content
|
203
|
+
</li>
|
204
|
+
<li>
|
205
|
+
The <code class="text-xs bg-muted px-1 py-0.5 rounded">open_delay</code> prevents the card from appearing too quickly during casual mouse movements
|
206
|
+
</li>
|
207
|
+
<li>
|
208
|
+
The <code class="text-xs bg-muted px-1 py-0.5 rounded">close_delay</code> gives users time to move their mouse into the card content
|
209
|
+
</li>
|
210
|
+
<li>
|
211
|
+
Hover cards work well with Avatar, Badge, and other components to create rich previews
|
212
|
+
</li>
|
213
|
+
<li>
|
214
|
+
Content should be concise but can include multiple elements like images, text, and metadata
|
215
|
+
</li>
|
216
|
+
</ul>
|
217
|
+
</div>
|
218
|
+
</div>
|
219
|
+
<% end %>
|
220
|
+
<% end %>
|