shadcn-ui 0.0.1 → 0.0.3

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/.env +1 -0
  3. data/.prettierrc.json +6 -0
  4. data/README.md +260 -0
  5. data/Rakefile +6 -3
  6. data/app/assets/stylesheets/{application.scss → application.css} +0 -27
  7. data/app/assets/stylesheets/application.tailwind.css +46 -73
  8. data/app/assets/stylesheets/shadcn.css +216 -0
  9. data/app/controllers/components_controller.rb +1 -1
  10. data/app/controllers/documentation_controller.rb +10 -0
  11. data/app/helpers/application_helper.rb +19 -0
  12. data/app/helpers/components/accordion_helper.rb +14 -1
  13. data/app/helpers/components/alert_helper.rb +4 -2
  14. data/app/helpers/components/button_helper.rb +2 -1
  15. data/app/helpers/components/card_helper.rb +2 -2
  16. data/app/helpers/components/checkbox_helper.rb +2 -2
  17. data/app/helpers/components/collapsible_helper.rb +8 -0
  18. data/app/helpers/components/filter_helper.rb +12 -0
  19. data/app/helpers/components/input_helper.rb +21 -0
  20. data/app/helpers/components/label_helper.rb +5 -0
  21. data/app/helpers/components/list_helper.rb +15 -0
  22. data/app/helpers/components/progress_helper.rb +5 -0
  23. data/app/helpers/components/sheet_helper.rb +29 -0
  24. data/app/helpers/components/skeleton_helper.rb +5 -0
  25. data/app/helpers/components/slider_helper.rb +5 -0
  26. data/app/helpers/components_helper.rb +11 -0
  27. data/app/helpers/documentation_helper.rb +2 -0
  28. data/app/helpers/examples_helper.rb +1 -2
  29. data/app/javascript/controllers/theme_controller.js +25 -0
  30. data/app/javascript/controllers/ui/dialog_controller.js +3 -1
  31. data/app/javascript/controllers/ui/dropdown_controller.js +2 -22
  32. data/app/javascript/controllers/ui/filter_controller.js +20 -0
  33. data/app/javascript/controllers/ui/popover_controller.js +29 -1
  34. data/app/javascript/controllers/ui/sheet_controller.js +33 -0
  35. data/app/javascript/controllers/ui/slider_controller.js +14 -0
  36. data/app/javascript/controllers/ui/tooltip_controller.js +1 -1
  37. data/app/views/application/index.html.erb +122 -0
  38. data/app/views/components/ui/_accordion.html.erb +2 -2
  39. data/app/views/components/ui/_alert.html.erb +15 -3
  40. data/app/views/components/ui/_alert_dialog.html.erb +1 -1
  41. data/app/views/components/ui/_card.html.erb +2 -2
  42. data/app/views/components/ui/_checkbox.html.erb +3 -7
  43. data/app/views/components/ui/_collapsible.html.erb +2 -6
  44. data/app/views/components/ui/_command.html.erb +0 -0
  45. data/app/views/components/ui/_dialog.html.erb +1 -1
  46. data/app/views/components/ui/_filter.html.erb +14 -0
  47. data/app/views/components/ui/_input.html.erb +8 -0
  48. data/app/views/components/ui/_label.html.erb +3 -0
  49. data/app/views/components/ui/_list.html.erb +5 -0
  50. data/app/views/components/ui/_progress.html.erb +15 -0
  51. data/app/views/components/ui/_sheet.html.erb +44 -0
  52. data/app/views/components/ui/_skeleton.html.erb +1 -0
  53. data/app/views/components/ui/_slider.html.erb +2 -0
  54. data/app/views/components/ui/_textarea.html.erb +1 -1
  55. data/app/views/components/ui/shared/{_dialog_background.html.erb → _backdrop.html.erb} +1 -0
  56. data/app/views/components/ui/svg/_check.html.erb +11 -0
  57. data/app/views/documentation/about.html.md +20 -0
  58. data/app/views/documentation/generators.html.md +1 -0
  59. data/app/views/documentation/index.html.erb.bak +70 -0
  60. data/app/views/documentation/index.html.md +37 -0
  61. data/app/views/documentation/installation.html.md +377 -0
  62. data/app/views/examples/components/accordion/_usage.html.erb +15 -0
  63. data/app/views/examples/components/accordion/code/_block.html.erb +8 -0
  64. data/app/views/examples/components/accordion/code/_description.html.erb +7 -0
  65. data/app/views/examples/components/accordion/code/preview.erb +3 -0
  66. data/app/views/examples/components/accordion/code/usage.erb +16 -0
  67. data/app/views/examples/components/accordion.html.erb +36 -0
  68. data/app/views/examples/components/alert/_usage.html.erb +10 -0
  69. data/app/views/examples/components/alert/code/_attention.erb +3 -0
  70. data/app/views/examples/components/alert/code/_destructive.erb +2 -0
  71. data/app/views/examples/components/alert/code/_info.erb +3 -0
  72. data/app/views/examples/components/alert/code/_no_icon.erb +3 -0
  73. data/app/views/examples/components/alert/code/_success.erb +3 -0
  74. data/app/views/examples/components/alert/code/preview.erb +2 -0
  75. data/app/views/examples/components/alert/code/usage.erb +1 -0
  76. data/app/views/examples/components/alert.html.erb +90 -7
  77. data/app/views/examples/components/badge/_usage.html.erb +10 -0
  78. data/app/views/examples/components/badge/code/preview.erb +5 -0
  79. data/app/views/examples/components/badge/code/usage.erb +1 -0
  80. data/app/views/examples/components/badge.html.erb +11 -4
  81. data/app/views/examples/components/button/_usage.html.erb +19 -0
  82. data/app/views/examples/components/button/code/preview.erb +13 -0
  83. data/app/views/examples/components/button/code/usage.erb +6 -0
  84. data/app/views/examples/components/button.html.erb +20 -6
  85. data/app/views/examples/components/card/_usage.html.erb +21 -0
  86. data/app/views/examples/components/card/code/_form.erb +72 -0
  87. data/app/views/examples/components/card/code/_notifications.erb +61 -0
  88. data/app/views/examples/components/card/code/preview.erb +6 -0
  89. data/app/views/examples/components/card/code/usage.erb +3 -0
  90. data/app/views/examples/components/card.html.erb +35 -143
  91. data/app/views/examples/components/checkbox/_usage.html.erb +9 -0
  92. data/app/views/examples/components/checkbox/code/preview.erb +2 -0
  93. data/app/views/examples/components/checkbox/code/usage.erb +1 -0
  94. data/app/views/examples/components/checkbox.html.erb +14 -0
  95. data/app/views/examples/components/collapsible/_usage.html.erb +16 -0
  96. data/app/views/examples/components/collapsible/code/preview.erb +9 -0
  97. data/app/views/examples/components/collapsible/code/usage.erb +7 -0
  98. data/app/views/examples/components/collapsible.html.erb +13 -3
  99. data/app/views/examples/components/dialog.html.erb +1 -1
  100. data/app/views/examples/components/filter.html.erb +25 -0
  101. data/app/views/examples/components/input.html.erb +18 -0
  102. data/app/views/examples/components/label.html.erb +13 -0
  103. data/app/views/examples/components/progress.html.erb +12 -0
  104. data/app/views/examples/components/sheet.html.erb +19 -0
  105. data/app/views/examples/components/skeleton.html.erb +12 -0
  106. data/app/views/examples/components/slider.html.erb +12 -0
  107. data/app/views/layouts/application.html.erb +2 -3
  108. data/app/views/layouts/component.html.erb +2 -2
  109. data/app/views/layouts/documentation.html.erb +39 -0
  110. data/app/views/layouts/shared/_components.html.erb +62 -0
  111. data/app/views/layouts/shared/_header.html.erb +25 -33
  112. data/app/views/layouts/shared/_sidebar.html.erb +10 -0
  113. data/config/application.rb +2 -1
  114. data/config/importmap.rb +6 -6
  115. data/config/initializers/markdown.rb +24 -0
  116. data/config/routes.rb +7 -1
  117. data/config/shadcn.tailwind.js +98 -0
  118. data/config/tailwind.config.js +13 -74
  119. data/lib/components.json +305 -0
  120. data/lib/generators/shadcn-ui_generator.rb +201 -0
  121. data/lib/shadcn-ui/version.rb +1 -1
  122. data/package-lock.json +90 -3
  123. data/package.json +4 -0
  124. data/public/accordion.png +0 -0
  125. metadata +81 -7
  126. data/app/views/layouts/_sidebar.html.erb +0 -270
  127. data/lib/generators/shadcn_ui_generator.rb +0 -32
  128. /data/app/assets/stylesheets/{lambda.light.scss → lambda.light.css} +0 -0
@@ -0,0 +1,10 @@
1
+ class DocumentationController < ActionController::Base
2
+ layout "documentation"
3
+ def index
4
+ end
5
+
6
+ def show
7
+ binding.pry
8
+ render "documentation/#{params[:id]}"
9
+ end
10
+ end
@@ -1,2 +1,21 @@
1
1
  module ApplicationHelper
2
+ def page_title
3
+ @page_title = ""
4
+ if request.path.include?("/docs/components")
5
+ component_name = params[:component].to_s.titleize
6
+ @page_title << "#{component_name} - " if component_name.present?
7
+ end
8
+ @page_title << "shadcn/ui on Rails"
9
+ @page_title
10
+ end
11
+
12
+ def sidebar_link(text, path)
13
+ classes = "group flex w-full items-center rounded-md border border-transparent px-2 py-1 hover:underline"
14
+ classes << if request.path == path
15
+ " text-foreground font-bold"
16
+ else
17
+ " text-muted-foreground"
18
+ end
19
+ link_to text, path, class: classes
20
+ end
2
21
  end
@@ -1,5 +1,18 @@
1
1
  module Components::AccordionHelper
2
- def render_accordion(title:, description:)
2
+ def accordion_title(&block)
3
+ content_for :title, capture(&block), flush: true
4
+ end
5
+
6
+ def accordion_description(&block)
7
+ content_for :description, capture(&block), flush: true
8
+ end
9
+
10
+ def render_accordion(title: nil, description: nil, &block)
11
+ if title && !description
12
+ content_for :description, capture(&block), flush: true
13
+ elsif !title && !description
14
+ capture(&block)
15
+ end
3
16
  render "components/ui/accordion", title: title, description: description
4
17
  end
5
18
  end
@@ -1,11 +1,13 @@
1
1
  module Components::AlertHelper
2
- def render_alert(title:, description:, variant: :default)
2
+ def render_alert(title:, description:, variant: :default, icon: true)
3
3
  alert_classes = case variant.to_sym
4
4
  when :default
5
5
  "[&>svg]:text-foreground bg-background text-foreground"
6
6
  when :error, :danger, :alert, :destructive
7
7
  "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"
8
+ else
9
+ "border-#{variant}/50 text-#{variant} dark:border-#{variant} [&>svg]:text-#{variant}"
8
10
  end
9
- render "components/ui/alert", title: title, description: description, alert_classes: alert_classes, variant: variant
11
+ render "components/ui/alert", title:, description:, alert_classes:, variant:, icon:
10
12
  end
11
13
  end
@@ -1,5 +1,5 @@
1
1
  module Components::ButtonHelper
2
- def render_button(label = "", data: "", text: "", variant: :default, as: :button, href: nil, **options)
2
+ def render_button(label = "", text: nil, variant: :default, as: :button, href: nil, data: {}, **options, &block)
3
3
  button_classes = " inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 h-10 px-4 py-2 "
4
4
  varianet_classes = case variant.to_sym
5
5
  when :default
@@ -15,6 +15,7 @@ module Components::ButtonHelper
15
15
  end
16
16
  button_classes << " #{varianet_classes} #{options[:class]}"
17
17
  text = label if label.present?
18
+ text = capture(&block) if block
18
19
  render "components/ui/button", text:, button_classes:, as:, href:, data:, **options
19
20
  end
20
21
  end
@@ -1,5 +1,5 @@
1
1
  module Components::CardHelper
2
- def render_card(footer: nil, title: nil, subtitle: nil, body: nil, **options, &block)
3
- render "components/ui/card", title: title, subtitle: subtitle, footer: footer, body: (block ? capture(&block) : body), block:, **options
2
+ def render_card(title: nil, subtitle: nil, body: nil, footer: nil, **options, &block)
3
+ render "components/ui/card", title: title, subtitle: subtitle, footer: footer, body: (block ? capture(&block) : body), block:, options: options
4
4
  end
5
5
  end
@@ -1,5 +1,5 @@
1
1
  module Components::CheckboxHelper
2
- def render_checkbox(label:, name:)
3
- render "components/ui/checkbox", name: name, label: label
2
+ def render_checkbox(label:, name:, **options)
3
+ render "components/ui/checkbox", name: name, label: label, options: options
4
4
  end
5
5
  end
@@ -1,4 +1,12 @@
1
1
  module Components::CollapsibleHelper
2
+ def collapsible_preview(&block)
3
+ content_for :preview, capture(&block) if block
4
+ end
5
+
6
+ def collapsible_body(&block)
7
+ content_for :body, capture(&block) if block
8
+ end
9
+
2
10
  def render_collapsible(**options, &block)
3
11
  content = capture(&block) if block
4
12
  render "components/ui/collapsible", content: content, **options
@@ -0,0 +1,12 @@
1
+ module Components::FilterHelper
2
+ def filter_icon(&block)
3
+ content_for :filter_icon, capture(&block), flush: true
4
+ end
5
+
6
+ def render_filter(items, **options, &block)
7
+ content_for :filter_icon, "", flush: true
8
+ content = capture(&block) if block
9
+ input_class = content_for?(:filter_icon) ? "pl-1" : ""
10
+ render "components/ui/filter", items: items, options: options, input_class: input_class, content: content
11
+ end
12
+ end
@@ -0,0 +1,21 @@
1
+ module Components::InputHelper
2
+ def render_input(name:, label: false, id: nil, type: :text, value: nil, **options)
3
+ options[:class] = "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50 #{options[:class]} "
4
+ options[:class] << case options[:style]
5
+ when :borderless
6
+ " border-0 focus-visible:outline-none focus-visible:shadow-none focus-visible:ring-transparent"
7
+ else
8
+ " focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:border-muted"
9
+ end
10
+ options.reverse_merge!(required: false, disabled: false,
11
+ readonly: false, label: false, placeholder: "Type here...")
12
+ render partial: "components/ui/input", locals: {
13
+ type:,
14
+ label:,
15
+ name:,
16
+ value:,
17
+ id:,
18
+ options: options
19
+ }
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ module Components::LabelHelper
2
+ def render_label(name:, label:, **options)
3
+ render "components/ui/label", name: name, label: label, options: options
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ module Components::ListHelper
2
+ def list_item(value:, name:, selected: false, as: :div)
3
+ content_tag as, value,
4
+ class: "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm
5
+ outline-none aria-selected:bg-accent aria-selected:text-accent-foreground hover:bg-accent hover:text-accent-foreground
6
+ data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
7
+ role: "option",
8
+ data: {value:, selected:},
9
+ aria: {selected:}
10
+ end
11
+
12
+ def render_list(items, as: :div, **options)
13
+ render "components/ui/list", items:, as:, **options
14
+ end
15
+ end
@@ -0,0 +1,5 @@
1
+ module Components::ProgressHelper
2
+ def render_progress(value:, **options)
3
+ render "components/ui/progress", value: (100 - value), **options
4
+ end
5
+ end
@@ -0,0 +1,29 @@
1
+ module Components::SheetHelper
2
+ def render_sheet(**options, &block)
3
+ options[:direction] ||= "left"
4
+ options[:width] ||= "w-3/4"
5
+
6
+ content_for :sheet_trigger, "", flush: true
7
+ content_for :sheet_content, "", flush: true
8
+
9
+ content = capture(&block) if block
10
+ render "components/ui/sheet", content: content, options: options
11
+ end
12
+
13
+ def sheet_trigger(&block)
14
+ content_for :sheet_trigger, capture(&block), flush: true
15
+ end
16
+
17
+ def sheet_content(&block)
18
+ content_for :sheet_content, capture(&block), flush: true
19
+ end
20
+
21
+ def direction_class(direction)
22
+ mappings = {
23
+ "left": 'left-0',
24
+ "right": 'right-0'
25
+ }
26
+
27
+ mappings[direction.to_sym]
28
+ end
29
+ end
@@ -0,0 +1,5 @@
1
+ module Components::SkeletonHelper
2
+ def render_skeleton
3
+ render "components/ui/skeleton"
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Components::SliderHelper
2
+ def render_slider(value:, id:, name:, **options)
3
+ render "components/ui/slider", value:, id:, name:, **options
4
+ end
5
+ end
@@ -4,4 +4,15 @@ module ComponentsHelper
4
4
  OUTLINE_CLASSES = " border border-input bg-background hover:bg-accent hover:text-accent-foreground "
5
5
  GHOST_CLASSES = " hover:bg-accent hover:text-accent-foreground "
6
6
  DESTRUCTIVE_CLASSES = " bg-destructive text-destructive-foreground hover:bg-destructive/90 "
7
+
8
+ module Button
9
+ PRIMARY = " bg-primary text-primary-foreground hover:bg-primary/80 "
10
+ SECONDARY = " bg-secondary text-secondary-foreground hover:bg-secondary/80 "
11
+ OUTLINE = " border border-input bg-background hover:bg-accent hover:text-accent-foreground "
12
+ GHOST = " hover:bg-accent hover:text-accent-foreground "
13
+ DESTRUCTIVE = " bg-destructive text-destructive-foreground hover:bg-destructive/90 "
14
+ end
15
+
16
+ module Alert
17
+ end
7
18
  end
@@ -0,0 +1,2 @@
1
+ module DocumentationHelper
2
+ end
@@ -24,9 +24,8 @@ module ExamplesHelper
24
24
  end
25
25
 
26
26
  def code_sample(content = "", language:, &block)
27
- content_tag :pre, class: "code-sample px-4 my-2 pb-5", data: {controller: "highlight"} do
27
+ content_tag :pre, class: "code-sample px-4 my-2 pb-5 min-h-fit", data: {controller: "highlight"} do
28
28
  content_tag :code, class: "language-#{language}" do
29
- content
30
29
  yield if block
31
30
  end
32
31
  end
@@ -0,0 +1,25 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class extends Controller {
4
+ static targets = ["toggleButton"];
5
+
6
+ connect() {
7
+ this.loadThemePreference();
8
+ }
9
+
10
+ toggle() {
11
+ const isDarkMode = document.documentElement.classList.toggle("dark");
12
+ this.saveThemePreference(isDarkMode);
13
+ }
14
+
15
+ loadThemePreference() {
16
+ const isDarkMode = localStorage.getItem("themePreference") === "true";
17
+ if (isDarkMode) {
18
+ document.documentElement.classList.add("dark");
19
+ }
20
+ }
21
+
22
+ saveThemePreference(isDarkMode) {
23
+ localStorage.setItem("themePreference", isDarkMode);
24
+ }
25
+ }
@@ -2,7 +2,7 @@
2
2
  import { Controller } from "@hotwired/stimulus";
3
3
  import "@kanety/stimulus-static-actions";
4
4
 
5
- export default class extends Controller {
5
+ export default class UIDialog extends Controller {
6
6
  static targets = ["dialog", "modal", "focus", "drag", "backdrop", "closeButton"];
7
7
  static actions = [
8
8
  ["element", "keydown@window->closeByKey"],
@@ -64,6 +64,8 @@ export default class extends Controller {
64
64
  this.dispatch("closed", { detail: { target: target } });
65
65
  }
66
66
 
67
+ // Refactor Me
68
+ // This needs to be combined with the toggle method in sheet_controller
67
69
  toggleClass(visible) {
68
70
  if (visible) {
69
71
  this.dialogTarget.classList.remove("hidden");
@@ -1,25 +1,5 @@
1
1
  // Inspired By: https://github.com/stimulus-components/stimulus-dropdown/blob/master/src/index.ts
2
- import { Controller } from "@hotwired/stimulus";
2
+ import UIPopover from "controllers/ui/popover_controller";
3
3
  import { useTransition } from "stimulus-use";
4
4
 
5
- export default class extends Controller {
6
- // menuTarget: HTMLElement
7
- // toggleTransition: (event?: Event) => void
8
- // leave: (event?: Event) => void
9
- // transitioned: false
10
- // static targets = ['menu']
11
- // connect (): void {
12
- // useTransition(this, {
13
- // element: this.menuTarget
14
- // })
15
- // }
16
- // toggle (): void {
17
- // this.toggleTransition()
18
- // }
19
- // hide (event: Event): void {
20
- // // @ts-ignore
21
- // if (!this.element.contains(event.target) && !this.menuTarget.classList.contains('hidden')) {
22
- // this.leave()
23
- // }
24
- // }
25
- }
5
+ export default class extends UIPopover {}
@@ -0,0 +1,20 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class UIFilter extends Controller {
4
+ static targets = ["source", "item"];
5
+
6
+ connect() {}
7
+
8
+ filter(event) {
9
+ let lowerCaseFilterTerm = this.sourceTarget.value.toLowerCase();
10
+ let regex = new RegExp("^" + lowerCaseFilterTerm);
11
+ if (this.hasItemTarget) {
12
+ this.itemTargets.forEach((el, i) => {
13
+ let filterableKey = el.innerText.toLowerCase();
14
+
15
+ // Check for consecutive characters match using regex
16
+ el.classList.toggle("hidden", !regex.test(filterableKey));
17
+ });
18
+ }
19
+ }
20
+ }
@@ -3,7 +3,7 @@
3
3
  import { Controller } from "@hotwired/stimulus";
4
4
  import { createPopper } from "@popperjs/core";
5
5
 
6
- export default class extends Controller {
6
+ export default class UIPopover extends Controller {
7
7
  static values = {
8
8
  dismissAfter: Number,
9
9
  };
@@ -24,4 +24,32 @@ export default class extends Controller {
24
24
  ],
25
25
  });
26
26
  }
27
+
28
+ // Show the popover
29
+ show() {
30
+ this.contentTarget.classList.remove("hidden");
31
+ this.contentTarget.dataset.state = "open";
32
+ }
33
+
34
+ // Hide the popover
35
+ hide() {
36
+ this.contentTarget.classList.add("hidden");
37
+ this.contentTarget.dataset.state = "closed";
38
+ }
39
+
40
+ // Toggle the popover on demand
41
+ toggle(event) {
42
+ this.popperInstance.update();
43
+ if (this.contentTarget.classList.contains("hidden")) {
44
+ this.show();
45
+
46
+ if (this.hasDismissAfterValue) {
47
+ setTimeout(() => {
48
+ this.hide();
49
+ }, this.dismissAfterValue);
50
+ }
51
+ } else {
52
+ this.hide();
53
+ }
54
+ }
27
55
  }
@@ -0,0 +1,33 @@
1
+ import UIDialog from "controllers/ui/dialog_controller";
2
+ import "@kanety/stimulus-static-actions";
3
+
4
+ export default class extends UIDialog {
5
+ // Handles a button triggering the sheet in a different
6
+ // controller instance
7
+ // REFACTOR: This is the toggle method in dialog_controller with dom elements
8
+ // instead of targets. Update the method there to receive dom elements and this
9
+ // can be refactored to use those methods instead of reimplementing.
10
+ toggleOutlet() {
11
+ const sheetTarget = document.querySelector(this.element.dataset.UiSheetOutlet);
12
+ const dialogTarget = sheetTarget.querySelector("[data-ui--sheet-target='dialog']");
13
+ const modalTarget = sheetTarget.querySelector("[data-ui--sheet-target='modal']");
14
+ const contentTarget = sheetTarget.querySelector("[data-ui--sheet-target='content']");
15
+ const visible = dialogTarget.dataset.state == "closed" ? false : true;
16
+ const mainTarget = document.body;
17
+ if (!visible) {
18
+ document.body.classList.add("overflow-hidden");
19
+ contentTarget.classList.add("overflow-y-scroll", "h-full");
20
+ dialogTarget.classList.remove("hidden");
21
+ dialogTarget.dataset.state = "open";
22
+ modalTarget.classList.remove("hidden");
23
+ modalTarget.dataset.state = "open";
24
+ } else {
25
+ document.body.classList.remove("overflow-hidden");
26
+ contentTarget.classList.remove("overflow-y-scroll", "h-full");
27
+ dialogTarget.classList.add("hidden");
28
+ dialogTarget.dataset.state = "closed";
29
+ modalTarget.classList.add("hidden");
30
+ modalTarget.dataset.state = "closed";
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,14 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+
3
+ export default class UISliderController extends Controller {
4
+ updateRange() {
5
+ const input = this.element;
6
+ const min = input.min;
7
+ const max = input.max;
8
+ const val = input.value;
9
+
10
+ const fillRatio = parseInt(((val - min) * 100) / (max - min));
11
+ input.style = `background-size: ${fillRatio}% 100%`;
12
+ input.setAttribute("value", fillRatio);
13
+ }
14
+ }
@@ -1,3 +1,3 @@
1
- import UIHoverCardController from "./hover-card_controller";
1
+ import UIHoverCardController from "controllers/ui/hover-card_controller";
2
2
 
3
3
  export default class UITooltipController extends UIHoverCardController {}
@@ -0,0 +1,122 @@
1
+ <div class="flex-1">
2
+ <div class="container relative">
3
+ <section class="flex max-w-[980px] flex-col items-start gap-2 pt-8 md:pt-12 pb-8">
4
+ <a
5
+ class="inline-flex items-center rounded-lg bg-muted px-3 py-1 text-sm font-medium"
6
+ href="/docs">🎉
7
+ <div
8
+ data-orientation="vertical"
9
+ role="none"
10
+ class="shrink-0 bg-border w-[1px] mx-2 h-4">
11
+ </div>
12
+ <span class="sm:hidden">Style, a new CLI and more.</span>
13
+ <span class="hidden sm:inline">Introducing shadcn/ui on Rails!</span>
14
+ <svg
15
+ width="15"
16
+ height="15"
17
+ viewBox="0 0 15 15"
18
+ fill="none"
19
+ xmlns="http://www.w3.org/2000/svg"
20
+ class="ml-1 h-4 w-4">
21
+ <path
22
+ d="M8.14645 3.14645C8.34171 2.95118 8.65829 2.95118 8.85355 3.14645L12.8536 7.14645C13.0488 7.34171 13.0488 7.65829 12.8536 7.85355L8.85355 11.8536C8.65829 12.0488 8.34171 12.0488 8.14645 11.8536C7.95118 11.6583 7.95118 11.3417 8.14645 11.1464L11.2929 8H2.5C2.22386 8 2 7.77614 2 7.5C2 7.22386 2.22386 7 2.5 7H11.2929L8.14645 3.85355C7.95118 3.65829 7.95118 3.34171 8.14645 3.14645Z"
23
+ fill="currentColor"
24
+ fill-rule="evenodd"
25
+ clip-rule="evenodd"></path>
26
+ </svg>
27
+ </a>
28
+ <h1 class="text-3xl font-bold leading-tight tracking-tighter md:text-5xl lg:leading-[1.1]">
29
+ Build your component library.
30
+ </h1>
31
+ <span
32
+ class="max-w-[750px] text-lg text-muted-foreground sm:text-xl"
33
+ data-br=":R1ir9hja:"
34
+ data-brr="1"
35
+ style="
36
+ display: inline-block;
37
+ vertical-align: top;
38
+ text-decoration: inherit;
39
+ max-width: 586px;">
40
+ Beautifully designed components based on <a href="https://ui.shadcn.com">shadcn/ui</a> that
41
+ you can copy and paste into your apps. Accessible. Customizable. Open Source.
42
+ </span>
43
+
44
+ <div class="flex w-full items-center space-x-4 pb-8 pt-4 md:pb-10">
45
+ <a
46
+ class="inline-flex items-center justify-center 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 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-9 px-4 py-2"
47
+ href="/docs">Get Started
48
+ </a>
49
+ <a
50
+ target="_blank"
51
+ rel="noreferrer"
52
+ class="inline-flex items-center justify-center 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 border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground h-9 px-4 py-2"
53
+ href="https://github.com/aviflombaum/shadcn-rails">
54
+ <svg
55
+ viewBox="0 0 438.549 438.549"
56
+ class="mr-2 h-4 w-4">
57
+ <path
58
+ fill="currentColor"
59
+ d="M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z">
60
+ </path>
61
+ </svg>GitHub
62
+ </a>
63
+ </div>
64
+ </section>
65
+ <section class="pt-8 md:pt-12 pb-8">
66
+ <div className="overflow-hidden rounded-[0.5rem] border border-1 bg-background shadow">
67
+ <div class="flex-1 space-y-4 p-8 pt-6 rounded-[0.5rem] border border-1 bg-background shadow">
68
+ <div class="flex items-center justify-between space-y-2">
69
+ <h2 class="text-3xl font-bold tracking-tight">Dashboard</h2>
70
+ <div class="flex items-center space-x-2">
71
+ <div class="grid gap-2"><button class="inline-flex items-center rounded-md text-sm transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground h-9 px-4 py-2 w-[260px] justify-start text-left font-normal" id="date" type="button" aria-haspopup="dialog" aria-expanded="false" aria-controls="radix-:r7:" data-state="closed"><svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" class="mr-2 h-4 w-4"><path d="M4.5 1C4.77614 1 5 1.22386 5 1.5V2H10V1.5C10 1.22386 10.2239 1 10.5 1C10.7761 1 11 1.22386 11 1.5V2H12.5C13.3284 2 14 2.67157 14 3.5V12.5C14 13.3284 13.3284 14 12.5 14H2.5C1.67157 14 1 13.3284 1 12.5V3.5C1 2.67157 1.67157 2 2.5 2H4V1.5C4 1.22386 4.22386 1 4.5 1ZM10 3V3.5C10 3.77614 10.2239 4 10.5 4C10.7761 4 11 3.77614 11 3.5V3H12.5C12.7761 3 13 3.22386 13 3.5V5H2V3.5C2 3.22386 2.22386 3 2.5 3H4V3.5C4 3.77614 4.22386 4 4.5 4C4.77614 4 5 3.77614 5 3.5V3H10ZM2 6V12.5C2 12.7761 2.22386 13 2.5 13H12.5C12.7761 13 13 12.7761 13 12.5V6H2ZM7 7.5C7 7.22386 7.22386 7 7.5 7C7.77614 7 8 7.22386 8 7.5C8 7.77614 7.77614 8 7.5 8C7.22386 8 7 7.77614 7 7.5ZM9.5 7C9.22386 7 9 7.22386 9 7.5C9 7.77614 9.22386 8 9.5 8C9.77614 8 10 7.77614 10 7.5C10 7.22386 9.77614 7 9.5 7ZM11 7.5C11 7.22386 11.2239 7 11.5 7C11.7761 7 12 7.22386 12 7.5C12 7.77614 11.7761 8 11.5 8C11.2239 8 11 7.77614 11 7.5ZM11.5 9C11.2239 9 11 9.22386 11 9.5C11 9.77614 11.2239 10 11.5 10C11.7761 10 12 9.77614 12 9.5C12 9.22386 11.7761 9 11.5 9ZM9 9.5C9 9.22386 9.22386 9 9.5 9C9.77614 9 10 9.22386 10 9.5C10 9.77614 9.77614 10 9.5 10C9.22386 10 9 9.77614 9 9.5ZM7.5 9C7.22386 9 7 9.22386 7 9.5C7 9.77614 7.22386 10 7.5 10C7.77614 10 8 9.77614 8 9.5C8 9.22386 7.77614 9 7.5 9ZM5 9.5C5 9.22386 5.22386 9 5.5 9C5.77614 9 6 9.22386 6 9.5C6 9.77614 5.77614 10 5.5 10C5.22386 10 5 9.77614 5 9.5ZM3.5 9C3.22386 9 3 9.22386 3 9.5C3 9.77614 3.22386 10 3.5 10C3.77614 10 4 9.77614 4 9.5C4 9.22386 3.77614 9 3.5 9ZM3 11.5C3 11.2239 3.22386 11 3.5 11C3.77614 11 4 11.2239 4 11.5C4 11.7761 3.77614 12 3.5 12C3.22386 12 3 11.7761 3 11.5ZM5.5 11C5.22386 11 5 11.2239 5 11.5C5 11.7761 5.22386 12 5.5 12C5.77614 12 6 11.7761 6 11.5C6 11.2239 5.77614 11 5.5 11ZM7 11.5C7 11.2239 7.22386 11 7.5 11C7.77614 11 8 11.2239 8 11.5C8 11.7761 7.77614 12 7.5 12C7.22386 12 7 11.7761 7 11.5ZM9.5 11C9.22386 11 9 11.2239 9 11.5C9 11.7761 9.22386 12 9.5 12C9.77614 12 10 11.7761 10 11.5C10 11.2239 9.77614 11 9.5 11Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>Jan 20, 2023 - Feb 09, 2023</button></div>
72
+ <button class="inline-flex items-center justify-center 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 bg-primary text-primary-foreground shadow hover:bg-primary/90 h-9 px-4 py-2">Download</button></div>
73
+ </div>
74
+ <div dir="ltr" data-orientation="horizontal" class="space-y-4">
75
+ <div role="tablist" aria-orientation="horizontal" class="inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground" tabindex="0" data-orientation="horizontal" style="outline: none;"><button type="button" role="tab" aria-selected="true" aria-controls="radix-:r8:-content-overview" data-state="active" id="radix-:r8:-trigger-overview" class="inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">Overview</button><button type="button" role="tab" aria-selected="false" aria-controls="radix-:r8:-content-analytics" data-state="inactive" data-disabled="" disabled="" id="radix-:r8:-trigger-analytics" class="inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">Analytics</button><button type="button" role="tab" aria-selected="false" aria-controls="radix-:r8:-content-reports" data-state="inactive" data-disabled="" disabled="" id="radix-:r8:-trigger-reports" class="inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">Reports</button><button type="button" role="tab" aria-selected="false" aria-controls="radix-:r8:-content-notifications" data-state="inactive" data-disabled="" disabled="" id="radix-:r8:-trigger-notifications" class="inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow" tabindex="-1" data-orientation="horizontal" data-radix-collection-item="">Notifications</button></div>
76
+ <div data-state="active" data-orientation="horizontal" role="tabpanel" aria-labelledby="radix-:r8:-trigger-overview" id="radix-:r8:-content-overview" tabindex="0" class="mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 space-y-4" style="">
77
+ <div class="grid gap-4 md:grid-cols-2 lg:grid-cols-4">
78
+ <div class="rounded-xl border bg-card text-card-foreground shadow">
79
+ <div class="p-6 flex flex-row items-center justify-between space-y-0 pb-2">
80
+ <h3 class="tracking-tight text-sm font-medium">Total Revenue</h3>
81
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="h-4 w-4 text-muted-foreground"><path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6"></path></svg></div>
82
+ <div class="p-6 pt-0">
83
+ <div class="text-2xl font-bold">$45,231.89</div>
84
+ <p class="text-xs text-muted-foreground">+20.1% from last month</p>
85
+ </div>
86
+ </div>
87
+ <div class="rounded-xl border bg-card text-card-foreground shadow">
88
+ <div class="p-6 flex flex-row items-center justify-between space-y-0 pb-2">
89
+ <h3 class="tracking-tight text-sm font-medium">Subscriptions</h3>
90
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="h-4 w-4 text-muted-foreground"><path d="M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2"></path><circle cx="9" cy="7" r="4"></circle><path d="M22 21v-2a4 4 0 0 0-3-3.87M16 3.13a4 4 0 0 1 0 7.75"></path></svg></div>
91
+ <div class="p-6 pt-0">
92
+ <div class="text-2xl font-bold">+2350</div>
93
+ <p class="text-xs text-muted-foreground">+180.1% from last month</p>
94
+ </div>
95
+ </div>
96
+ <div class="rounded-xl border bg-card text-card-foreground shadow">
97
+ <div class="p-6 flex flex-row items-center justify-between space-y-0 pb-2">
98
+ <h3 class="tracking-tight text-sm font-medium">Sales</h3>
99
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="h-4 w-4 text-muted-foreground"><rect width="20" height="14" x="2" y="5" rx="2"></rect><path d="M2 10h20"></path></svg></div>
100
+ <div class="p-6 pt-0">
101
+ <div class="text-2xl font-bold">+12,234</div>
102
+ <p class="text-xs text-muted-foreground">+19% from last month</p>
103
+ </div>
104
+ </div>
105
+ <div class="rounded-xl border bg-card text-card-foreground shadow">
106
+ <div class="p-6 flex flex-row items-center justify-between space-y-0 pb-2">
107
+ <h3 class="tracking-tight text-sm font-medium">Active Now</h3>
108
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" class="h-4 w-4 text-muted-foreground"><path d="M22 12h-4l-3 9L9 3l-3 9H2"></path></svg></div>
109
+ <div class="p-6 pt-0">
110
+ <div class="text-2xl font-bold">+573</div>
111
+ <p class="text-xs text-muted-foreground">+201 since last hour</p>
112
+ </div>
113
+ </div>
114
+ </div>
115
+
116
+ </div>
117
+ </div>
118
+ </div>
119
+ </div>
120
+ </section>
121
+ </div>
122
+ </div>
@@ -14,7 +14,7 @@
14
14
  aria-expanded="true"
15
15
  data-orientation="vertical"
16
16
  class="flex flex-1 items-center justify-between py-4 font-medium transition-all hover:underline [&[data-state=open]>svg]:rotate-180">
17
- <%= title %><svg
17
+ <%= title || content_for(:title) %><svg
18
18
  xmlns="http://www.w3.org/2000/svg"
19
19
  width="24"
20
20
  height="24"
@@ -34,7 +34,7 @@
34
34
  role="region"
35
35
  data-orientation="vertical"
36
36
  class="st-accordion__content overflow-hidden text-sm transition-all data-[state=closed]:animate-accordion-up data-[state=open]:animate-accordion-down">
37
- <div class="pb-4 pt-0"><%= description %></div>
37
+ <div class="pb-4 pt-0"><%= description || content_for(:description) %></div>
38
38
  </div>
39
39
  </div>
40
40
  </div>