agent-notes 2.0.4__py3-none-any.whl

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 (162) hide show
  1. agent_notes/VERSION +1 -0
  2. agent_notes/__init__.py +1 -0
  3. agent_notes/__main__.py +4 -0
  4. agent_notes/cli.py +348 -0
  5. agent_notes/commands/__init__.py +27 -0
  6. agent_notes/commands/_install_helpers.py +262 -0
  7. agent_notes/commands/build.py +170 -0
  8. agent_notes/commands/doctor.py +112 -0
  9. agent_notes/commands/info.py +95 -0
  10. agent_notes/commands/install.py +99 -0
  11. agent_notes/commands/list.py +169 -0
  12. agent_notes/commands/memory.py +430 -0
  13. agent_notes/commands/regenerate.py +152 -0
  14. agent_notes/commands/set_role.py +143 -0
  15. agent_notes/commands/uninstall.py +26 -0
  16. agent_notes/commands/update.py +169 -0
  17. agent_notes/commands/validate.py +199 -0
  18. agent_notes/commands/wizard.py +720 -0
  19. agent_notes/config.py +154 -0
  20. agent_notes/data/agents/agents.yaml +352 -0
  21. agent_notes/data/agents/analyst.md +45 -0
  22. agent_notes/data/agents/api-reviewer.md +47 -0
  23. agent_notes/data/agents/architect.md +46 -0
  24. agent_notes/data/agents/coder.md +28 -0
  25. agent_notes/data/agents/database-specialist.md +45 -0
  26. agent_notes/data/agents/debugger.md +47 -0
  27. agent_notes/data/agents/devil.md +47 -0
  28. agent_notes/data/agents/devops.md +38 -0
  29. agent_notes/data/agents/explorer.md +23 -0
  30. agent_notes/data/agents/integrations.md +44 -0
  31. agent_notes/data/agents/lead.md +216 -0
  32. agent_notes/data/agents/performance-profiler.md +44 -0
  33. agent_notes/data/agents/refactorer.md +48 -0
  34. agent_notes/data/agents/reviewer.md +44 -0
  35. agent_notes/data/agents/security-auditor.md +44 -0
  36. agent_notes/data/agents/system-auditor.md +38 -0
  37. agent_notes/data/agents/tech-writer.md +32 -0
  38. agent_notes/data/agents/test-runner.md +36 -0
  39. agent_notes/data/agents/test-writer.md +39 -0
  40. agent_notes/data/cli/claude.yaml +25 -0
  41. agent_notes/data/cli/copilot.yaml +18 -0
  42. agent_notes/data/cli/opencode.yaml +22 -0
  43. agent_notes/data/commands/brainstorm.md +8 -0
  44. agent_notes/data/commands/debug.md +9 -0
  45. agent_notes/data/commands/review.md +10 -0
  46. agent_notes/data/global-claude.md +290 -0
  47. agent_notes/data/global-copilot.md +27 -0
  48. agent_notes/data/global-opencode.md +40 -0
  49. agent_notes/data/hooks/session-context.md.tpl +19 -0
  50. agent_notes/data/models/claude-haiku-4-5.yaml +15 -0
  51. agent_notes/data/models/claude-opus-4-1.yaml +16 -0
  52. agent_notes/data/models/claude-opus-4-5.yaml +16 -0
  53. agent_notes/data/models/claude-opus-4-6.yaml +16 -0
  54. agent_notes/data/models/claude-opus-4-7.yaml +15 -0
  55. agent_notes/data/models/claude-sonnet-4-5.yaml +16 -0
  56. agent_notes/data/models/claude-sonnet-4-6.yaml +15 -0
  57. agent_notes/data/models/claude-sonnet-4.yaml +16 -0
  58. agent_notes/data/pricing.yaml +33 -0
  59. agent_notes/data/roles/orchestrator.yaml +5 -0
  60. agent_notes/data/roles/reasoner.yaml +5 -0
  61. agent_notes/data/roles/scout.yaml +5 -0
  62. agent_notes/data/roles/worker.yaml +5 -0
  63. agent_notes/data/rules/code-quality.md +9 -0
  64. agent_notes/data/rules/safety.md +10 -0
  65. agent_notes/data/scripts/cost-report +211 -0
  66. agent_notes/data/skills/brainstorming/SKILL.md +57 -0
  67. agent_notes/data/skills/code-review/SKILL.md +64 -0
  68. agent_notes/data/skills/debugging-protocol/SKILL.md +51 -0
  69. agent_notes/data/skills/docker-compose/SKILL.md +318 -0
  70. agent_notes/data/skills/docker-compose-advanced/SKILL.md +575 -0
  71. agent_notes/data/skills/docker-dockerfile/SKILL.md +385 -0
  72. agent_notes/data/skills/docker-dockerfile-languages/SKILL.md +293 -0
  73. agent_notes/data/skills/git/SKILL.md +87 -0
  74. agent_notes/data/skills/rails-active-storage/SKILL.md +321 -0
  75. agent_notes/data/skills/rails-broadcasting/SKILL.md +374 -0
  76. agent_notes/data/skills/rails-concerns/SKILL.md +806 -0
  77. agent_notes/data/skills/rails-controllers/SKILL.md +510 -0
  78. agent_notes/data/skills/rails-controllers-advanced/SKILL.md +441 -0
  79. agent_notes/data/skills/rails-helpers/SKILL.md +677 -0
  80. agent_notes/data/skills/rails-initializers/SKILL.md +79 -0
  81. agent_notes/data/skills/rails-javascript/SKILL.md +567 -0
  82. agent_notes/data/skills/rails-jobs/SKILL.md +700 -0
  83. agent_notes/data/skills/rails-kamal/SKILL.md +483 -0
  84. agent_notes/data/skills/rails-lib/SKILL.md +101 -0
  85. agent_notes/data/skills/rails-mailers/SKILL.md +321 -0
  86. agent_notes/data/skills/rails-migrations/SKILL.md +268 -0
  87. agent_notes/data/skills/rails-models/SKILL.md +459 -0
  88. agent_notes/data/skills/rails-models-advanced/SKILL.md +398 -0
  89. agent_notes/data/skills/rails-routes/SKILL.md +804 -0
  90. agent_notes/data/skills/rails-style/SKILL.md +538 -0
  91. agent_notes/data/skills/rails-testing-controllers/SKILL.md +343 -0
  92. agent_notes/data/skills/rails-testing-models/SKILL.md +296 -0
  93. agent_notes/data/skills/rails-testing-system/SKILL.md +375 -0
  94. agent_notes/data/skills/rails-validations/SKILL.md +108 -0
  95. agent_notes/data/skills/rails-view-components/SKILL.md +511 -0
  96. agent_notes/data/skills/rails-view-components-advanced/SKILL.md +376 -0
  97. agent_notes/data/skills/rails-views/SKILL.md +413 -0
  98. agent_notes/data/skills/rails-views-advanced/SKILL.md +450 -0
  99. agent_notes/data/skills/refactoring-protocol/SKILL.md +64 -0
  100. agent_notes/data/skills/tdd/SKILL.md +57 -0
  101. agent_notes/data/templates/__init__.py +1 -0
  102. agent_notes/data/templates/__pycache__/__init__.cpython-314.pyc +0 -0
  103. agent_notes/data/templates/frontmatter/__init__.py +1 -0
  104. agent_notes/data/templates/frontmatter/__pycache__/__init__.cpython-314.pyc +0 -0
  105. agent_notes/data/templates/frontmatter/__pycache__/claude.cpython-314.pyc +0 -0
  106. agent_notes/data/templates/frontmatter/__pycache__/cursor.cpython-314.pyc +0 -0
  107. agent_notes/data/templates/frontmatter/__pycache__/opencode.cpython-314.pyc +0 -0
  108. agent_notes/data/templates/frontmatter/claude.py +44 -0
  109. agent_notes/data/templates/frontmatter/opencode.py +104 -0
  110. agent_notes/doctor_checks.py +189 -0
  111. agent_notes/domain/__init__.py +17 -0
  112. agent_notes/domain/agent.py +34 -0
  113. agent_notes/domain/cli_backend.py +40 -0
  114. agent_notes/domain/diagnostics.py +29 -0
  115. agent_notes/domain/diff.py +44 -0
  116. agent_notes/domain/model.py +27 -0
  117. agent_notes/domain/role.py +13 -0
  118. agent_notes/domain/rule.py +13 -0
  119. agent_notes/domain/skill.py +15 -0
  120. agent_notes/domain/state.py +46 -0
  121. agent_notes/install_state.py +11 -0
  122. agent_notes/registries/__init__.py +16 -0
  123. agent_notes/registries/_base.py +46 -0
  124. agent_notes/registries/agent_registry.py +107 -0
  125. agent_notes/registries/cli_registry.py +89 -0
  126. agent_notes/registries/model_registry.py +85 -0
  127. agent_notes/registries/role_registry.py +64 -0
  128. agent_notes/registries/rule_registry.py +80 -0
  129. agent_notes/registries/skill_registry.py +141 -0
  130. agent_notes/services/__init__.py +8 -0
  131. agent_notes/services/diagnostics/__init__.py +47 -0
  132. agent_notes/services/diagnostics/_checks.py +272 -0
  133. agent_notes/services/diagnostics/_display.py +346 -0
  134. agent_notes/services/diagnostics/_fix.py +169 -0
  135. agent_notes/services/diff.py +349 -0
  136. agent_notes/services/fs.py +195 -0
  137. agent_notes/services/install_state_builder.py +210 -0
  138. agent_notes/services/installer.py +293 -0
  139. agent_notes/services/memory_backend.py +155 -0
  140. agent_notes/services/rendering.py +329 -0
  141. agent_notes/services/session_context.py +23 -0
  142. agent_notes/services/settings_writer.py +79 -0
  143. agent_notes/services/state_store.py +249 -0
  144. agent_notes/services/ui.py +419 -0
  145. agent_notes/services/user_config.py +62 -0
  146. agent_notes/services/validation.py +67 -0
  147. agent_notes/state.py +21 -0
  148. agent_notes-2.0.4.dist-info/METADATA +14 -0
  149. agent_notes-2.0.4.dist-info/RECORD +162 -0
  150. agent_notes-2.0.4.dist-info/WHEEL +5 -0
  151. agent_notes-2.0.4.dist-info/entry_points.txt +2 -0
  152. agent_notes-2.0.4.dist-info/licenses/LICENSE +21 -0
  153. agent_notes-2.0.4.dist-info/top_level.txt +2 -0
  154. tests/conftest.py +20 -0
  155. tests/functional/__init__.py +0 -0
  156. tests/functional/test_build_commands.py +88 -0
  157. tests/functional/test_registries.py +128 -0
  158. tests/integration/__init__.py +0 -0
  159. tests/integration/test_build_output.py +129 -0
  160. tests/plugins/__init__.py +0 -0
  161. tests/plugins/test_agents.py +93 -0
  162. tests/plugins/test_skills.py +77 -0
@@ -0,0 +1,511 @@
1
+ ---
2
+ name: rails-view-components
3
+ description: "ViewComponent: reusable components, slots, testing, and previews"
4
+ group: rails
5
+ ---
6
+
7
+ # ViewComponent
8
+
9
+ A framework for building reusable, testable & encapsulated view components in Ruby on Rails.
10
+
11
+ > **Source**: This guide is based on [ViewComponent Official Documentation](https://viewcomponent.org/) and the [ViewComponent GitHub Repository](https://github.com/ViewComponent/view_component).
12
+
13
+ ---
14
+
15
+ ## Philosophy
16
+
17
+ **"ViewComponent is to UI what ActiveRecord is to SQL"** — brings conceptual compression to UI development.
18
+
19
+ ViewComponent was created to manage complexity in GitHub.com's view layer, providing abstraction for common UI patterns to improve quality and consistency. It exposes existing complexity, which aids refactoring and comprehension.
20
+
21
+ **Key Benefits:**
22
+ - **Over 100x faster** than similar controller tests (GitHub codebase)
23
+ - **Reusable** - Build once, use anywhere
24
+ - **Testable** - Unit test with `render_inline`
25
+ - **Encapsulated** - Self-contained logic and templates
26
+
27
+ **Source**: [ViewComponent Overview](https://viewcomponent.org/)
28
+
29
+ ---
30
+
31
+ ## File Structure
32
+
33
+ ```
34
+ app/components/
35
+ ├── application_component.rb # Base component
36
+ ├── button_component.rb # Component class
37
+ ├── button_component.html.erb # Component template
38
+ ├── card_component.rb
39
+ ├── card_component/
40
+ │ ├── card_component.html.erb # Sidecar template
41
+ │ ├── header_component.rb # Nested component
42
+ │ └── header_component.html.erb
43
+ └── alert/
44
+ ├── component.rb # Alternative structure
45
+ └── component.html.erb
46
+ ```
47
+
48
+ ---
49
+
50
+ ## Basic Component Structure
51
+
52
+ ### Simple Component
53
+
54
+ ```ruby
55
+ # app/components/button_component.rb
56
+ class ButtonComponent < ViewComponent::Base
57
+ def initialize(type: :primary, size: :medium, **html_options)
58
+ @type = type
59
+ @size = size
60
+ @html_options = html_options
61
+ end
62
+
63
+ private
64
+ attr_reader :type, :size, :html_options
65
+
66
+ def button_classes
67
+ [
68
+ "btn",
69
+ "btn-#{type}",
70
+ "btn-#{size}",
71
+ html_options[:class]
72
+ ].compact.join(" ")
73
+ end
74
+ end
75
+ ```
76
+
77
+ ```erb
78
+ <%# app/components/button_component.html.erb %>
79
+ <button class="<%= button_classes %>" <%= tag.attributes(html_options.except(:class)) %>>
80
+ <%= content %>
81
+ </button>
82
+ ```
83
+
84
+ **Usage:**
85
+ ```erb
86
+ <%= render ButtonComponent.new(type: :primary, size: :large, data: { action: "click->form#submit" }) do %>
87
+ Submit Form
88
+ <% end %>
89
+ ```
90
+
91
+ ### Component with Slots
92
+
93
+ ```ruby
94
+ # app/components/card_component.rb
95
+ class CardComponent < ViewComponent::Base
96
+ # Single slot (rendered at most once)
97
+ renders_one :header, HeaderComponent
98
+
99
+ # Multiple slots (rendered multiple times)
100
+ renders_many :actions, ActionComponent
101
+
102
+ def initialize(variant: :default)
103
+ @variant = variant
104
+ end
105
+
106
+ private
107
+ attr_reader :variant
108
+ end
109
+ ```
110
+
111
+ ```erb
112
+ <%# app/components/card_component.html.erb %>
113
+ <div class="card card-<%= variant %>">
114
+ <% if header? %>
115
+ <div class="card-header">
116
+ <%= header %>
117
+ </div>
118
+ <% end %>
119
+
120
+ <div class="card-body">
121
+ <%= content %>
122
+ </div>
123
+
124
+ <% if actions? %>
125
+ <div class="card-actions">
126
+ <% actions.each do |action| %>
127
+ <%= action %>
128
+ <% end %>
129
+ </div>
130
+ <% end %>
131
+ </div>
132
+ ```
133
+
134
+ **Usage:**
135
+ ```erb
136
+ <%= render CardComponent.new(variant: :primary) do |card| %>
137
+ <% card.with_header(title: "User Profile") %>
138
+
139
+ <p>This is the card body content.</p>
140
+
141
+ <% card.with_action(label: "Edit", url: edit_user_path(@user)) %>
142
+ <% card.with_action(label: "Delete", url: user_path(@user), method: :delete) %>
143
+ <% end %>
144
+ ```
145
+
146
+ **Source**: [ViewComponent Slots Guide](https://viewcomponent.org/guide/slots.html)
147
+
148
+ ---
149
+
150
+ ## Slot Patterns
151
+
152
+ ### renders_one (Single Slot)
153
+
154
+ ```ruby
155
+ class AlertComponent < ViewComponent::Base
156
+ # Simple passthrough slot
157
+ renders_one :title
158
+
159
+ # Component slot
160
+ renders_one :icon, IconComponent
161
+
162
+ # Lambda slot
163
+ renders_one :footer, ->(text:, classes: nil) do
164
+ content_tag :div, text, class: classes
165
+ end
166
+ end
167
+ ```
168
+
169
+ ```erb
170
+ <div class="alert">
171
+ <% if icon? %>
172
+ <%= icon %>
173
+ <% end %>
174
+
175
+ <% if title? %>
176
+ <h4><%= title %></h4>
177
+ <% end %>
178
+
179
+ <%= content %>
180
+
181
+ <% if footer? %>
182
+ <%= footer %>
183
+ <% end %>
184
+ </div>
185
+ ```
186
+
187
+ **Usage:**
188
+ ```erb
189
+ <%= render AlertComponent.new do |alert| %>
190
+ <% alert.with_icon(name: "warning") %>
191
+ <% alert.with_title { "Warning" } %>
192
+
193
+ This is an alert message.
194
+
195
+ <% alert.with_footer(text: "Dismiss", classes: "text-sm") %>
196
+ <% end %>
197
+ ```
198
+
199
+ ### renders_many (Multiple Slots)
200
+
201
+ ```ruby
202
+ class NavigationComponent < ViewComponent::Base
203
+ # Multiple items
204
+ renders_many :items, NavItemComponent
205
+
206
+ # Or with lambda
207
+ renders_many :links, ->(title:, url:, **options) do
208
+ link_to title, url, options
209
+ end
210
+ end
211
+ ```
212
+
213
+ ```erb
214
+ <nav>
215
+ <ul>
216
+ <% items.each do |item| %>
217
+ <li><%= item %></li>
218
+ <% end %>
219
+ </ul>
220
+ </nav>
221
+ ```
222
+
223
+ **Usage:**
224
+ ```erb
225
+ <%= render NavigationComponent.new do |nav| %>
226
+ <% nav.with_item(title: "Home", url: root_path, current: true) %>
227
+ <% nav.with_item(title: "About", url: about_path) %>
228
+ <% nav.with_item(title: "Contact", url: contact_path) %>
229
+ <% end %>
230
+ ```
231
+
232
+ ### Polymorphic Slots
233
+
234
+ ```ruby
235
+ class ModalComponent < ViewComponent::Base
236
+ renders_one :body, types: {
237
+ text: ->(content:) { content_tag :p, content },
238
+ form: FormComponent,
239
+ custom: ->(&block) { capture(&block) }
240
+ }
241
+ end
242
+ ```
243
+
244
+ **Usage:**
245
+ ```erb
246
+ <%# Text variant %>
247
+ <%= render ModalComponent.new do |modal| %>
248
+ <% modal.with_body_text(content: "Simple text content") %>
249
+ <% end %>
250
+
251
+ <%# Form variant %>
252
+ <%= render ModalComponent.new do |modal| %>
253
+ <% modal.with_body_form(url: users_path) %>
254
+ <% end %>
255
+
256
+ <%# Custom variant %>
257
+ <%= render ModalComponent.new do |modal| %>
258
+ <% modal.with_body_custom do %>
259
+ <div>Custom HTML content</div>
260
+ <% end %>
261
+ <% end %>
262
+ ```
263
+
264
+ **Source**: [ViewComponent Slots - Polymorphic Slots](https://viewcomponent.org/guide/slots.html)
265
+
266
+ ---
267
+
268
+ ## Slot Utilities
269
+
270
+ ### Predicate Methods
271
+
272
+ ```ruby
273
+ class CardComponent < ViewComponent::Base
274
+ renders_one :header
275
+ renders_many :actions
276
+ end
277
+ ```
278
+
279
+ ```erb
280
+ <% if header? %>
281
+ <%= header %>
282
+ <% end %>
283
+
284
+ <% if actions? %>
285
+ <% actions.each do |action| %>
286
+ <%= action %>
287
+ <% end %>
288
+ <% end %>
289
+ ```
290
+
291
+ ### Default Slots
292
+
293
+ ```ruby
294
+ class PanelComponent < ViewComponent::Base
295
+ renders_one :title
296
+
297
+ private
298
+ def default_title
299
+ content_tag :h3, "Default Title"
300
+ end
301
+ end
302
+ ```
303
+
304
+ ```erb
305
+ <%# Will use default if not provided %>
306
+ <%= title %>
307
+ ```
308
+
309
+ ### Collection Rendering
310
+
311
+ ```ruby
312
+ class TableComponent < ViewComponent::Base
313
+ renders_many :rows
314
+ end
315
+ ```
316
+
317
+ **Usage:**
318
+ ```erb
319
+ <%= render TableComponent.new do |table| %>
320
+ <%# Pass array to plural setter %>
321
+ <% table.with_rows(@users.map { |user| { name: user.name, email: user.email } }) %>
322
+ <% end %>
323
+ ```
324
+
325
+ **Source**: [ViewComponent Slots Guide](https://viewcomponent.org/guide/slots.html)
326
+
327
+ ---
328
+
329
+ ## Testing
330
+
331
+ ### Basic Component Test
332
+
333
+ ```ruby
334
+ # test/components/button_component_test.rb
335
+ require "test_helper"
336
+
337
+ class ButtonComponentTest < ViewComponent::TestCase
338
+ def test_renders_button
339
+ render_inline ButtonComponent.new(type: :primary) do
340
+ "Click me"
341
+ end
342
+
343
+ assert_selector "button.btn.btn-primary", text: "Click me"
344
+ end
345
+
346
+ def test_renders_with_custom_classes
347
+ render_inline ButtonComponent.new(type: :secondary, class: "custom-class")
348
+
349
+ assert_selector "button.btn.btn-secondary.custom-class"
350
+ end
351
+
352
+ def test_renders_with_data_attributes
353
+ render_inline ButtonComponent.new(data: { action: "click->test#run" })
354
+
355
+ assert_selector "button[data-action='click->test#run']"
356
+ end
357
+ end
358
+ ```
359
+
360
+ ### Testing with Slots
361
+
362
+ ```ruby
363
+ class CardComponentTest < ViewComponent::TestCase
364
+ def test_renders_with_header
365
+ render_inline CardComponent.new do |card|
366
+ card.with_header(title: "Test Card")
367
+ "Card content"
368
+ end
369
+
370
+ assert_selector ".card-header", text: "Test Card"
371
+ assert_selector ".card-body", text: "Card content"
372
+ end
373
+
374
+ def test_renders_without_header
375
+ render_inline CardComponent.new do
376
+ "Card content"
377
+ end
378
+
379
+ assert_no_selector ".card-header"
380
+ assert_selector ".card-body", text: "Card content"
381
+ end
382
+
383
+ def test_renders_multiple_actions
384
+ render_inline CardComponent.new do |card|
385
+ card.with_action(label: "Edit")
386
+ card.with_action(label: "Delete")
387
+ end
388
+
389
+ assert_selector ".card-actions", count: 1
390
+ assert_text "Edit"
391
+ assert_text "Delete"
392
+ end
393
+ end
394
+ ```
395
+
396
+ ### RSpec Setup
397
+
398
+ ```ruby
399
+ # spec/rails_helper.rb
400
+ RSpec.configure do |config|
401
+ config.include ViewComponent::TestHelpers, type: :component
402
+ config.include Capybara::RSpecMatchers, type: :component
403
+ end
404
+ ```
405
+
406
+ ```ruby
407
+ # spec/components/button_component_spec.rb
408
+ require "rails_helper"
409
+
410
+ RSpec.describe ButtonComponent, type: :component do
411
+ it "renders a primary button" do
412
+ render_inline described_class.new(type: :primary) do
413
+ "Submit"
414
+ end
415
+
416
+ expect(page).to have_css "button.btn.btn-primary", text: "Submit"
417
+ end
418
+
419
+ it "applies custom data attributes" do
420
+ render_inline described_class.new(data: { controller: "form" })
421
+
422
+ expect(page).to have_css "button[data-controller='form']"
423
+ end
424
+ end
425
+ ```
426
+
427
+ **Source**: [ViewComponent Testing Guide](https://viewcomponent.org/guide/testing.html)
428
+
429
+ ---
430
+
431
+ ## Previews
432
+
433
+ Previews provide a quick way to visualize components in isolation during development.
434
+
435
+ ### Creating Previews
436
+
437
+ ```ruby
438
+ # test/components/previews/button_component_preview.rb
439
+ class ButtonComponentPreview < ViewComponent::Preview
440
+ # Default preview
441
+ def default
442
+ render ButtonComponent.new(type: :primary) do
443
+ "Default Button"
444
+ end
445
+ end
446
+
447
+ # Named preview
448
+ def primary
449
+ render ButtonComponent.new(type: :primary) do
450
+ "Primary Button"
451
+ end
452
+ end
453
+
454
+ def secondary
455
+ render ButtonComponent.new(type: :secondary) do
456
+ "Secondary Button"
457
+ end
458
+ end
459
+
460
+ def large
461
+ render ButtonComponent.new(type: :primary, size: :large) do
462
+ "Large Button"
463
+ end
464
+ end
465
+
466
+ # With description
467
+ # @label Danger Button
468
+ # @display bg_color "#fee"
469
+ def danger
470
+ render ButtonComponent.new(type: :danger) do
471
+ "Danger Button"
472
+ end
473
+ end
474
+ end
475
+ ```
476
+
477
+ ### Preview with Slots
478
+
479
+ ```ruby
480
+ class CardComponentPreview < ViewComponent::Preview
481
+ def with_all_slots
482
+ render CardComponent.new(variant: :primary) do |card|
483
+ card.with_header(title: "Card Title")
484
+ card.with_action(label: "Edit", url: "#")
485
+ card.with_action(label: "Delete", url: "#")
486
+
487
+ "This is the card body content with all slots populated."
488
+ end
489
+ end
490
+
491
+ def minimal
492
+ render CardComponent.new do
493
+ "Minimal card with no slots."
494
+ end
495
+ end
496
+ end
497
+ ```
498
+
499
+ ### Configuration
500
+
501
+ ```ruby
502
+ # config/application.rb
503
+ config.view_component.preview_paths << "#{Rails.root}/app/components/previews"
504
+ config.view_component.show_previews = Rails.env.development?
505
+ ```
506
+
507
+ **Access previews:** Visit `/rails/view_components` in development.
508
+
509
+ **Source**: [ViewComponent Previews Guide](https://viewcomponent.org/guide/previews.html)
510
+
511
+ ---