ruby_ui 1.0.1 → 1.1.0

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 (122) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +6 -0
  4. data/lib/generators/ruby_ui/component/all_generator.rb +22 -0
  5. data/lib/generators/ruby_ui/component_generator.rb +4 -3
  6. data/lib/generators/ruby_ui/install/docs_generator.rb +33 -0
  7. data/lib/generators/ruby_ui/install/install_generator.rb +1 -7
  8. data/lib/generators/ruby_ui/install/templates/tailwind.css.erb +0 -3
  9. data/lib/generators/ruby_ui/javascript_utils.rb +4 -0
  10. data/lib/ruby_ui/accordion/accordion_docs.rb +53 -0
  11. data/lib/ruby_ui/alert/alert_docs.rb +135 -0
  12. data/lib/ruby_ui/alert_dialog/alert_dialog_content.rb +2 -3
  13. data/lib/ruby_ui/alert_dialog/alert_dialog_docs.rb +35 -0
  14. data/lib/ruby_ui/aspect_ratio/aspect_ratio_docs.rb +64 -0
  15. data/lib/ruby_ui/avatar/avatar_docs.rb +92 -0
  16. data/lib/ruby_ui/badge/badge_docs.rb +80 -0
  17. data/lib/ruby_ui/breadcrumb/breadcrumb_docs.rb +116 -0
  18. data/lib/ruby_ui/button/button.rb +32 -16
  19. data/lib/ruby_ui/button/button_docs.rb +143 -0
  20. data/lib/ruby_ui/calendar/calendar_docs.rb +34 -0
  21. data/lib/ruby_ui/card/card_docs.rb +114 -0
  22. data/lib/ruby_ui/carousel/carousel_docs.rb +104 -0
  23. data/lib/ruby_ui/chart/chart_docs.rb +115 -0
  24. data/lib/ruby_ui/checkbox/checkbox.rb +7 -1
  25. data/lib/ruby_ui/checkbox/checkbox_docs.rb +41 -0
  26. data/lib/ruby_ui/clipboard/clipboard_docs.rb +30 -0
  27. data/lib/ruby_ui/codeblock/codeblock_docs.rb +55 -0
  28. data/lib/ruby_ui/collapsible/collapsible_docs.rb +96 -0
  29. data/lib/ruby_ui/combobox/combobox.rb +3 -2
  30. data/lib/ruby_ui/combobox/combobox_checkbox.rb +4 -2
  31. data/lib/ruby_ui/combobox/combobox_controller.js +20 -5
  32. data/lib/ruby_ui/combobox/combobox_docs.rb +151 -0
  33. data/lib/ruby_ui/combobox/combobox_item.rb +2 -1
  34. data/lib/ruby_ui/combobox/combobox_popover.rb +2 -1
  35. data/lib/ruby_ui/combobox/combobox_radio.rb +8 -1
  36. data/lib/ruby_ui/combobox/combobox_search_input.rb +11 -5
  37. data/lib/ruby_ui/combobox/combobox_toggle_all_checkbox.rb +4 -2
  38. data/lib/ruby_ui/combobox/combobox_trigger.rb +8 -2
  39. data/lib/ruby_ui/command/command_controller.js +0 -1
  40. data/lib/ruby_ui/command/command_docs.rb +154 -0
  41. data/lib/ruby_ui/context_menu/context_menu.rb +1 -1
  42. data/lib/ruby_ui/context_menu/context_menu_docs.rb +85 -0
  43. data/lib/ruby_ui/dialog/dialog_content.rb +2 -3
  44. data/lib/ruby_ui/dialog/dialog_controller.js +1 -1
  45. data/lib/ruby_ui/dialog/dialog_docs.rb +102 -0
  46. data/lib/ruby_ui/docs/base.rb +90 -0
  47. data/lib/ruby_ui/docs/component_setup_tabs.rb +15 -0
  48. data/lib/ruby_ui/docs/components_table.rb +13 -0
  49. data/lib/ruby_ui/docs/header.rb +17 -0
  50. data/lib/ruby_ui/docs/sidebar_examples.rb +22 -0
  51. data/lib/ruby_ui/docs/visual_code_example.rb +22 -0
  52. data/lib/ruby_ui/dropdown_menu/dropdown_menu.rb +9 -0
  53. data/lib/ruby_ui/dropdown_menu/dropdown_menu_content.rb +17 -2
  54. data/lib/ruby_ui/dropdown_menu/dropdown_menu_controller.js +43 -14
  55. data/lib/ruby_ui/dropdown_menu/dropdown_menu_docs.rb +212 -0
  56. data/lib/ruby_ui/form/form_docs.rb +178 -0
  57. data/lib/ruby_ui/form/form_field.rb +1 -1
  58. data/lib/ruby_ui/form/form_field_error.rb +1 -1
  59. data/lib/ruby_ui/form/form_field_hint.rb +1 -1
  60. data/lib/ruby_ui/form/form_field_label.rb +7 -1
  61. data/lib/ruby_ui/hover_card/hover_card_docs.rb +71 -0
  62. data/lib/ruby_ui/input/input.rb +9 -1
  63. data/lib/ruby_ui/input/input_docs.rb +68 -0
  64. data/lib/ruby_ui/link/link.rb +32 -16
  65. data/lib/ruby_ui/link/link_docs.rb +106 -0
  66. data/lib/ruby_ui/masked_input/masked_input_docs.rb +47 -0
  67. data/lib/ruby_ui/pagination/pagination_docs.rb +127 -0
  68. data/lib/ruby_ui/popover/popover_docs.rb +971 -0
  69. data/lib/ruby_ui/progress/progress_docs.rb +27 -0
  70. data/lib/ruby_ui/radio_button/radio_button.rb +3 -1
  71. data/lib/ruby_ui/radio_button/radio_button_docs.rb +53 -0
  72. data/lib/ruby_ui/select/select_docs.rb +129 -0
  73. data/lib/ruby_ui/select/select_item.rb +14 -5
  74. data/lib/ruby_ui/select/select_trigger.rb +9 -4
  75. data/lib/ruby_ui/separator/separator_docs.rb +36 -0
  76. data/lib/ruby_ui/sheet/sheet_content.rb +1 -1
  77. data/lib/ruby_ui/sheet/sheet_docs.rb +76 -0
  78. data/lib/ruby_ui/shortcut_key/shortcut_key_docs.rb +29 -0
  79. data/lib/ruby_ui/sidebar/collapsible_sidebar.rb +99 -0
  80. data/lib/ruby_ui/sidebar/mobile_sidebar.rb +45 -0
  81. data/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb +17 -0
  82. data/lib/ruby_ui/sidebar/sidebar.rb +29 -0
  83. data/lib/ruby_ui/sidebar/sidebar_content.rb +20 -0
  84. data/lib/ruby_ui/sidebar/sidebar_controller.js +67 -0
  85. data/lib/ruby_ui/sidebar/sidebar_docs.rb +176 -0
  86. data/lib/ruby_ui/sidebar/sidebar_footer.rb +20 -0
  87. data/lib/ruby_ui/sidebar/sidebar_group.rb +20 -0
  88. data/lib/ruby_ui/sidebar/sidebar_group_action.rb +33 -0
  89. data/lib/ruby_ui/sidebar/sidebar_group_content.rb +20 -0
  90. data/lib/ruby_ui/sidebar/sidebar_group_label.rb +26 -0
  91. data/lib/ruby_ui/sidebar/sidebar_header.rb +20 -0
  92. data/lib/ruby_ui/sidebar/sidebar_input.rb +20 -0
  93. data/lib/ruby_ui/sidebar/sidebar_inset.rb +23 -0
  94. data/lib/ruby_ui/sidebar/sidebar_menu.rb +20 -0
  95. data/lib/ruby_ui/sidebar/sidebar_menu_action.rb +48 -0
  96. data/lib/ruby_ui/sidebar/sidebar_menu_badge.rb +30 -0
  97. data/lib/ruby_ui/sidebar/sidebar_menu_button.rb +63 -0
  98. data/lib/ruby_ui/sidebar/sidebar_menu_item.rb +20 -0
  99. data/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb +36 -0
  100. data/lib/ruby_ui/sidebar/sidebar_menu_sub.rb +24 -0
  101. data/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb +50 -0
  102. data/lib/ruby_ui/sidebar/sidebar_menu_sub_item.rb +9 -0
  103. data/lib/ruby_ui/sidebar/sidebar_rail.rb +36 -0
  104. data/lib/ruby_ui/sidebar/sidebar_separator.rb +20 -0
  105. data/lib/ruby_ui/sidebar/sidebar_trigger.rb +42 -0
  106. data/lib/ruby_ui/sidebar/sidebar_wrapper.rb +24 -0
  107. data/lib/ruby_ui/skeleton/skeleton_docs.rb +29 -0
  108. data/lib/ruby_ui/switch/switch.rb +12 -2
  109. data/lib/ruby_ui/switch/switch_docs.rb +46 -0
  110. data/lib/ruby_ui/table/table_docs.rb +102 -0
  111. data/lib/ruby_ui/table/table_footer.rb +1 -1
  112. data/lib/ruby_ui/table/table_row.rb +1 -1
  113. data/lib/ruby_ui/tabs/tabs_docs.rb +211 -0
  114. data/lib/ruby_ui/tabs/tabs_trigger.rb +7 -1
  115. data/lib/ruby_ui/textarea/textarea.rb +8 -1
  116. data/lib/ruby_ui/textarea/textarea_docs.rb +54 -0
  117. data/lib/ruby_ui/theme_toggle/theme_toggle_docs.rb +71 -0
  118. data/lib/ruby_ui/tooltip/tooltip_controller.js +5 -4
  119. data/lib/ruby_ui/tooltip/tooltip_docs.rb +52 -0
  120. data/lib/ruby_ui/typography/typography_docs.rb +107 -0
  121. data/lib/ruby_ui.rb +1 -1
  122. metadata +81 -6
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class SidebarMenuSubButton < Base
5
+ SIZE_CLASSES = {
6
+ sm: "text-xs",
7
+ md: "text-sm"
8
+ }.freeze
9
+
10
+ def initialize(as: :button, size: :md, active: false, **attrs)
11
+ raise ArgumentError, "Invalid size: #{size}" unless SIZE_CLASSES.key?(size)
12
+
13
+ @as = as
14
+ @size = size
15
+ @active = active
16
+ super(**attrs)
17
+ end
18
+
19
+ def view_template(&)
20
+ tag(@as, **attrs, &)
21
+ end
22
+
23
+ private
24
+
25
+ def default_attrs
26
+ {
27
+ class: [
28
+ "flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden",
29
+ "rounded-md px-2 text-sidebar-foreground outline-none",
30
+ "ring-sidebar-ring hover:bg-sidebar-accent",
31
+ "hover:text-sidebar-accent-foreground focus-visible:ring-2",
32
+ "active:bg-sidebar-accent active:text-sidebar-accent-foreground",
33
+ "disabled:pointer-events-none disabled:opacity-50",
34
+ "aria-disabled:pointer-events-none aria-disabled:opacity-50",
35
+ "[&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
36
+ "[&>svg]:text-sidebar-accent-foreground",
37
+ "data-[active=true]:bg-sidebar-accent",
38
+ "data-[active=true]:text-sidebar-accent-foreground",
39
+ "group-data-[collapsible=icon]:hidden",
40
+ SIZE_CLASSES[@size]
41
+ ],
42
+ data: {
43
+ sidebar: "menu-sub-button",
44
+ size: @size,
45
+ active: @active.to_s
46
+ }
47
+ }
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class SidebarMenuSubItem < Base
5
+ def view_template(&)
6
+ li(**attrs, &)
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class SidebarRail < Base
5
+ def view_template(&)
6
+ button(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: [
14
+ "absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all",
15
+ "ease-linear after:absolute after:inset-y-0 after:left-1/2",
16
+ "after:w-[2px] hover:after:bg-sidebar-border",
17
+ "group-data-[side=left]:-right-4 group-data-[side=right]:left-0",
18
+ "sm:flex [[data-side=left]_&]:cursor-w-resize",
19
+ "[[data-side=right]_&]:cursor-e-resize",
20
+ "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize",
21
+ "[[data-side=right][data-state=collapsed]_&]:cursor-w-resize",
22
+ "group-data-[collapsible=offcanvas]:translate-x-0",
23
+ "group-data-[collapsible=offcanvas]:after:left-full",
24
+ "group-data-[collapsible=offcanvas]:hover:bg-sidebar",
25
+ "[[data-side=left][data-collapsible=offcanvas]_&]:-right-2",
26
+ "[[data-side=right][data-collapsible=offcanvas]_&]:-left-2"
27
+ ],
28
+ data: {
29
+ sidebar: "rail",
30
+ tabindex: "-1",
31
+ action: "click->ruby-ui--sidebar#toggle"
32
+ }
33
+ }
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class SidebarSeparator < Base
5
+ def view_template(&)
6
+ Separator(**attrs, &)
7
+ end
8
+
9
+ private
10
+
11
+ def default_attrs
12
+ {
13
+ class: "mx-2 w-auto bg-sidebar-border",
14
+ data: {
15
+ sidebar: "separator"
16
+ }
17
+ }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class SidebarTrigger < Base
5
+ def view_template(&)
6
+ Button(variant: :ghost, size: :icon, **attrs) do
7
+ panel_left_icon
8
+ span(class: "sr-only") { "Toggle Sidebar" }
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def default_attrs
15
+ {
16
+ class: "h-7 w-7 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
17
+ data: {
18
+ sidebar: "trigger",
19
+ action: "click->ruby-ui--sidebar#toggle"
20
+ }
21
+ }
22
+ end
23
+
24
+ def panel_left_icon
25
+ svg(
26
+ xmlns: "http://www.w3.org/2000/svg",
27
+ width: "24",
28
+ height: "24",
29
+ viewBox: "0 0 24 24",
30
+ fill: "none",
31
+ stroke: "currentColor",
32
+ stroke_width: "2",
33
+ stroke_linecap: "round",
34
+ stroke_linejoin: "round",
35
+ class: "lucide lucide-panel-left"
36
+ ) do |s|
37
+ s.rect(width: "18", height: "18", x: "3", y: "3", rx: "2")
38
+ s.path(d: "M9 3v18")
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RubyUI
4
+ class SidebarWrapper < Base
5
+ SIDEBAR_WIDTH = "16rem"
6
+ SIDEBAR_WIDTH_ICON = "3rem"
7
+
8
+ def view_template(&)
9
+ div(**attrs, &)
10
+ end
11
+
12
+ private
13
+
14
+ def default_attrs
15
+ {
16
+ class: "group/sidebar-wrapper [&:has([data-variant=inset])]:bg-sidebar flex min-h-svh w-full",
17
+ style: "--sidebar-width: #{SIDEBAR_WIDTH}; --sidebar-width-icon: #{SIDEBAR_WIDTH_ICON};",
18
+ data: {
19
+ controller: "ruby-ui--sidebar"
20
+ }
21
+ }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::Skeleton < Views::Base
4
+ def view_template
5
+ component = "Skeleton"
6
+
7
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
8
+ render Docs::Header.new(title: "Skeleton", description: "Use to show a placeholder while content is loading.")
9
+
10
+ Heading(level: 2) { "Usage" }
11
+
12
+ render Docs::VisualCodeExample.new(title: "Example", context: self) do
13
+ <<~RUBY
14
+ div(class: "flex items-center space-x-4") do
15
+ Skeleton(class: "h-12 w-12 rounded-full")
16
+ div(class: "space-y-2") do
17
+ Skeleton(class: "h-4 w-[250px]")
18
+ Skeleton(class: "h-4 w-[200px]")
19
+ end
20
+ end
21
+ RUBY
22
+ end
23
+
24
+ render Components::ComponentSetup::Tabs.new(component_name: component)
25
+
26
+ render Docs::ComponentsTable.new(component_files(component))
27
+ end
28
+ end
29
+ end
@@ -12,12 +12,22 @@ module RubyUI
12
12
  def view_template
13
13
  label(
14
14
  role: "switch",
15
- class: "peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background has-[:disabled]:cursor-not-allowed has-[:disabled]:opacity-50 bg-input has-[:checked]:bg-primary"
15
+ class: [
16
+ "peer inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors bg-input",
17
+ "has-checked:bg-primary",
18
+ "has-disabled:cursor-not-allowed has-disabled:opacity-50",
19
+ "has-aria-disabled:cursor-not-allowed has-aria-disabled:opacity-50 has-aria-disabled:pointer-events-none",
20
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background"
21
+ ]
16
22
  ) do
17
23
  input(type: "hidden", name: attrs[:name], value: @unchecked_value) if @include_hidden
24
+
18
25
  input(**attrs.merge(type: "checkbox", class: "hidden peer", value: @checked_value))
19
26
 
20
- span(class: "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform translate-x-0 peer-checked:translate-x-5 ")
27
+ span(class: [
28
+ "pointer-events-none block h-5 w-5 rounded-full bg-background shadow-lg ring-0 transition-transform translate-x-0",
29
+ "peer-checked:translate-x-5"
30
+ ])
21
31
  end
22
32
  end
23
33
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::Switch < Views::Base
4
+ def view_template
5
+ component = "Switch"
6
+
7
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
8
+ render Docs::Header.new(title: "Switch", description: "A control that allows the user to toggle between checked and not checked.")
9
+
10
+ Heading(level: 2) { "Usage" }
11
+
12
+ render Docs::VisualCodeExample.new(title: "Default", context: self) do
13
+ <<~RUBY
14
+ Switch(name: "switch")
15
+ RUBY
16
+ end
17
+
18
+ render Docs::VisualCodeExample.new(title: "Checked", context: self) do
19
+ <<~RUBY
20
+ Switch(name: "switch", checked: true)
21
+ RUBY
22
+ end
23
+
24
+ render Docs::VisualCodeExample.new(title: "Disabled", context: self) do
25
+ <<~RUBY
26
+ Switch(name: "switch", disabled: true)
27
+ RUBY
28
+ end
29
+
30
+ render Docs::VisualCodeExample.new(title: "Aria Disabled", context: self) do
31
+ <<~RUBY
32
+ Switch(name: "switch", aria: {disabled: "true"})
33
+ RUBY
34
+ end
35
+
36
+ render Docs::VisualCodeExample.new(title: "With flag include_hidden false", context: self) do
37
+ <<~RUBY
38
+ # Supports the creation of a hidden input to be used in forms inspired by the Ruby on Rails implementation of check_box. Default is true.
39
+ Switch(name: "switch", include_hidden: false)
40
+ RUBY
41
+ end
42
+
43
+ render Docs::ComponentsTable.new(component_files(component))
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::Table < Views::Base
4
+ Invoice = Struct.new(:identifier, :status, :method, :amount, keyword_init: true)
5
+ User = Struct.new(:avatar_url, :name, :username, :commits, :github_url, keyword_init: true)
6
+
7
+ def view_template
8
+ component = "Table"
9
+
10
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-8") do
11
+ render Docs::Header.new(title: "Table", description: "A responsive table component.")
12
+
13
+ Heading(level: 2) { "Usage" }
14
+
15
+ render Docs::VisualCodeExample.new(title: "Without builder", context: self) do
16
+ <<~RUBY
17
+ Table do
18
+ TableCaption { "Employees at Acme inc." }
19
+ TableHeader do
20
+ TableRow do
21
+ TableHead { "Name" }
22
+ TableHead { "Email" }
23
+ TableHead { "Status" }
24
+ TableHead(class: "text-right") { "Role" }
25
+ end
26
+ end
27
+ TableBody do
28
+ invoices.each do |invoice|
29
+ TableRow do
30
+ TableCell(class: 'font-medium') { invoice.identifier }
31
+ TableCell { render_status_badge(invoice.status) }
32
+ TableCell { invoice.method }
33
+ TableCell(class: "text-right") { format_amount(invoice.amount) }
34
+ end
35
+ end
36
+ end
37
+ TableFooter do
38
+ TableRow do
39
+ TableHead(class: "font-medium", colspan: 3) { "Total" }
40
+ TableHead(class: "font-medium text-right") { format_amount(invoices.sum(&:amount)) }
41
+ end
42
+ end
43
+ end
44
+ RUBY
45
+ end
46
+
47
+ render Components::ComponentSetup::Tabs.new(component_name: component)
48
+
49
+ render Docs::ComponentsTable.new(component_files(component))
50
+ end
51
+ end
52
+
53
+ private
54
+
55
+ def invoices
56
+ [
57
+ Invoice.new(identifier: "INV-0001", status: "Active", method: "Credit Card", amount: 100),
58
+ Invoice.new(identifier: "INV-0002", status: "Active", method: "Bank Transfer", amount: 230),
59
+ Invoice.new(identifier: "INV-0003", status: "Pending", method: "PayPal", amount: 350),
60
+ Invoice.new(identifier: "INV-0004", status: "Inactive", method: "Credit Card", amount: 100)
61
+ ]
62
+ end
63
+
64
+ def users
65
+ [
66
+ User.new(avatar_url: "https://avatars.githubusercontent.com/u/246692?v=4", name: "Joel Drapper", username: "joeldrapper", commits: 404),
67
+ User.new(avatar_url: "https://avatars.githubusercontent.com/u/33979976?v=4", name: "Alexandre Ruban", username: "alexandreruban", commits: 16),
68
+ User.new(avatar_url: "https://avatars.githubusercontent.com/u/77887?v=4", name: "Will Cosgrove", username: "willcosgrove", commits: 12),
69
+ User.new(avatar_url: "https://avatars.githubusercontent.com/u/3025661?v=4", name: "Stephann V.", username: "stephannv", commits: 8),
70
+ User.new(avatar_url: "https://avatars.githubusercontent.com/u/6411752?v=4", name: "Marco Roth", username: "marcoroth", commits: 8)
71
+ ]
72
+ end
73
+
74
+ def github_link(user)
75
+ "https://github.com/#{user.username}"
76
+ end
77
+
78
+ def github_icon
79
+ svg(viewbox: "0 0 438.549 438.549", class: "h-4 w-4") do |s|
80
+ s.path(
81
+ fill: "currentColor",
82
+ d:
83
+ "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"
84
+ )
85
+ end
86
+ end
87
+
88
+ def format_amount(amount)
89
+ "$#{amount}.00"
90
+ end
91
+
92
+ def render_status_badge(status)
93
+ case status.downcase
94
+ when "active"
95
+ Badge(variant: :success, size: :sm) { status }
96
+ when "inactive"
97
+ Badge(variant: :destructive, size: :sm) { status }
98
+ when "pending"
99
+ Badge(variant: :warning, size: :sm) { status }
100
+ end
101
+ end
102
+ end
@@ -10,7 +10,7 @@ module RubyUI
10
10
 
11
11
  def default_attrs
12
12
  {
13
- class: "border-t bg-muted bg-opacity-50 font-medium[& amp;>tr]:last:border-b-0"
13
+ class: "border-t bg-muted/50 font-medium[& amp;>tr]:last:border-b-0"
14
14
  }
15
15
  end
16
16
  end
@@ -10,7 +10,7 @@ module RubyUI
10
10
 
11
11
  def default_attrs
12
12
  {
13
- class: "border-b transition-colors hover:bg-muted hover:bg-opacity-50 data-[state=selected]:bg-muted"
13
+ class: "border-b transition-colors hover:bg-muted/50 data-[state=selected]:bg-muted"
14
14
  }
15
15
  end
16
16
  end
@@ -0,0 +1,211 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Views::Docs::Tabs < Views::Base
4
+ Repo = Struct.new(:github_url, :name, :stars, :version, keyword_init: true)
5
+
6
+ def view_template
7
+ component = "Tabs"
8
+
9
+ div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
10
+ render Docs::Header.new(title: "Tabs", description: "A set of layered sections of content—known as tab panels—that are displayed one at a time.")
11
+
12
+ Heading(level: 2) { "Usage" }
13
+
14
+ render Docs::VisualCodeExample.new(title: "Example", context: self) do
15
+ <<~RUBY
16
+ Tabs(default_value: "account", class: 'w-96') do
17
+ TabsList do
18
+ TabsTrigger(value: "account") { "Account" }
19
+ TabsTrigger(value: "password") { "Password" }
20
+ end
21
+ TabsContent(value: "account") do
22
+ div(class: "rounded-lg border p-6 space-y-4 bg-background text-foreground") do
23
+ div(class: "space-y-0") do
24
+ Text(size: "4", weight: "semibold") { "Account" }
25
+ Text(size: "2", class: "text-muted-foreground") { "Update your account details." }
26
+ end
27
+ end
28
+ end
29
+ TabsContent(value: "password") do
30
+ div(class: "rounded-lg border p-6 space-y-4 bg-background text-foreground") do
31
+ div do
32
+ Text(size: "4", weight: "semibold") { "Password" }
33
+ Text(size: "2", class: "text-muted-foreground") { "Change your password here. After saving, you'll be logged out." }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ RUBY
39
+ end
40
+
41
+ render Docs::VisualCodeExample.new(title: "Disabled", context: self) do
42
+ <<~RUBY
43
+ Tabs(default_value: "account", class: 'w-96') do
44
+ TabsList do
45
+ TabsTrigger(disabled: true, value: "account") { "Account" }
46
+ TabsTrigger(disabled: true, value: "password") { "Password" }
47
+ end
48
+ end
49
+ RUBY
50
+ end
51
+
52
+ render Docs::VisualCodeExample.new(title: "Aria Disabled", context: self) do
53
+ <<~RUBY
54
+ Tabs(default_value: "account", class: 'w-96') do
55
+ TabsList do
56
+ TabsTrigger(aria: {disabled: "true"}, value: "account") { "Account" }
57
+ TabsTrigger(aria: {disabled: "true"}, value: "password") { "Password" }
58
+ end
59
+ end
60
+ RUBY
61
+ end
62
+
63
+ render Docs::VisualCodeExample.new(title: "Full width", context: self) do
64
+ <<~RUBY
65
+ Tabs(default_value: "overview", class: 'w-96') do
66
+ TabsList(class: 'w-full grid grid-cols-2') do
67
+ TabsTrigger(value: "overview") do
68
+ book_icon
69
+ span(class: 'ml-2') { "Overview" }
70
+ end
71
+ TabsTrigger(value: "repositories") do
72
+ repo_icon
73
+ span(class: 'ml-2') { "Repositories" }
74
+ end
75
+ end
76
+ TabsContent(value: "overview") do
77
+ div(class: "rounded-lg border p-6 bg-background text-foreground flex justify-between space-x-4") do
78
+ Avatar do
79
+ AvatarImage(src: "https://avatars.githubusercontent.com/u/246692?v=4", alt: "joeldrapper")
80
+ AvatarFallback { "JD" }
81
+ end
82
+ div(class: "space-y-4") do
83
+ div do
84
+ Text(size: "4", weight: "semibold") { "Joel Drapper" }
85
+ Text(size: "2", class: "text-muted-foreground") { "Creator of Phlex Components. Ruby on Rails developer." }
86
+ end
87
+ Link(href: "https://github.com/joeldrapper", variant: :outline, size: :sm) do
88
+ github_icon
89
+ span(class: 'ml-2') { "View profile" }
90
+ end
91
+ end
92
+ end
93
+ end
94
+ TabsContent(value: "repositories") do
95
+ div(class: "rounded-lg border p-6 space-y-4 bg-background text-foreground") do
96
+ repo = repositories.first
97
+ Link(href: repo.github_url, variant: :link, class: "pl-0") { repo.name }
98
+ Badge { repo.version }
99
+ end
100
+ end
101
+ end
102
+ RUBY
103
+ end
104
+
105
+ render Docs::VisualCodeExample.new(title: "Change default value", context: self) do
106
+ <<~RUBY
107
+ Tabs(default: "password", class: 'w-96') do
108
+ TabsList do
109
+ TabsTrigger(value: "account") { "Account" }
110
+ TabsTrigger(value: "password") { "Password" }
111
+ end
112
+ TabsContent(value: "account") do
113
+ div(class: "rounded-lg border p-6 space-y-4 bg-background text-foreground") do
114
+ div(class: "space-y-0") do
115
+ Text(size: "4", weight: "semibold") { "Account" }
116
+ Text(size: "2", class: "text-muted-foreground") { "Update your account details." }
117
+ end
118
+ end
119
+ end
120
+ TabsContent(value: "password") do
121
+ div(class: "rounded-lg border p-6 space-y-4 bg-background text-foreground") do
122
+ div do
123
+ Text(size: "4", weight: "semibold") { "Password" }
124
+ Text(size: "2", class: "text-muted-foreground") { "Change your password here. After saving, you'll be logged out." }
125
+ end
126
+ end
127
+ end
128
+ end
129
+ RUBY
130
+ end
131
+
132
+ render Components::ComponentSetup::Tabs.new(component_name: component)
133
+
134
+ render Docs::ComponentsTable.new(component_files(component))
135
+ end
136
+ end
137
+
138
+ private
139
+
140
+ def book_icon
141
+ svg(
142
+ xmlns: "http://www.w3.org/2000/svg",
143
+ fill: "none",
144
+ viewbox: "0 0 24 24",
145
+ stroke_width: "2",
146
+ stroke: "currentColor",
147
+ class: "w-4 h-4 text-muted-foreground"
148
+ ) do |s|
149
+ s.path(
150
+ stroke_linecap: "round",
151
+ stroke_linejoin: "round",
152
+ d:
153
+ "M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25"
154
+ )
155
+ end
156
+ end
157
+
158
+ def repo_icon
159
+ svg(
160
+ xmlns: "http://www.w3.org/2000/svg",
161
+ fill: "none",
162
+ viewbox: "0 0 24 24",
163
+ stroke_width: "2",
164
+ stroke: "currentColor",
165
+ class: "w-4 h-4 text-muted-foreground"
166
+ ) do |s|
167
+ s.path(
168
+ stroke_linecap: "round",
169
+ stroke_linejoin: "round",
170
+ d:
171
+ "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9"
172
+ )
173
+ end
174
+ end
175
+
176
+ def github_icon
177
+ svg(viewbox: "0 0 438.549 438.549", class: "h-4 w-4") do |s|
178
+ s.path(
179
+ fill: "currentColor",
180
+ d:
181
+ "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"
182
+ )
183
+ end
184
+ end
185
+
186
+ def star_icon
187
+ svg(
188
+ xmlns: "http://www.w3.org/2000/svg",
189
+ fill: "none",
190
+ viewbox: "0 0 24 24",
191
+ stroke_width: "2",
192
+ stroke: "currentColor",
193
+ class: "w-4 h-4 text-amber-500"
194
+ ) do |s|
195
+ s.path(
196
+ stroke_linecap: "round",
197
+ stroke_linejoin: "round",
198
+ d:
199
+ "M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z"
200
+ )
201
+ end
202
+ end
203
+
204
+ def repositories
205
+ [
206
+ Repo.new(github_url: "https://github.com/phlex-ruby/phlex", name: "phlex", stars: 961, version: "v1.8.1"),
207
+ Repo.new(github_url: "https://github.com/joeldrapper/green_dots", name: "green_dots", stars: 40, version: "1.0"),
208
+ Repo.new(github_url: "https://github.com/joeldrapper/literal", name: "literal", stars: 96, version: "v0.1.0")
209
+ ]
210
+ end
211
+ end
@@ -21,7 +21,13 @@ module RubyUI
21
21
  action: "click->ruby-ui--tabs#show",
22
22
  value: @value
23
23
  },
24
- 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"
24
+ class: [
25
+ "inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all",
26
+ "disabled:pointer-events-none disabled:opacity-50",
27
+ "aria-disabled:pointer-events-none aria-disabled:opacity-50 aria-disabled:cursor-not-allowed",
28
+ "data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
29
+ "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2"
30
+ ]
25
31
  }
26
32
  end
27
33
  end
@@ -19,7 +19,14 @@ module RubyUI
19
19
  ruby_ui__form_field_target: "input",
20
20
  action: "input->ruby-ui--form-field#onInput invalid->ruby-ui--form-field#onInvalid"
21
21
  },
22
- class: "flex w-full rounded-md border bg-background px-3 py-1 text-sm shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium focus-visible:outline-none focus-visible:ring-1 disabled:cursor-not-allowed disabled:opacity-50 border-border focus-visible:ring-ring placeholder:text-muted-foreground"
22
+ class: [
23
+ "flex w-full rounded-md border bg-background px-3 py-1 text-sm shadow-sm transition-colors border-border",
24
+ "placeholder:text-muted-foreground",
25
+ "disabled:cursor-not-allowed disabled:opacity-50",
26
+ "file:border-0 file:bg-transparent file:text-sm file:font-medium",
27
+ "focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring",
28
+ "aria-disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:pointer-events-none"
29
+ ]
23
30
  }
24
31
  end
25
32
  end