ruby_ui 1.0.2 → 1.2.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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +4 -0
- data/lib/generators/ruby_ui/component_generator.rb +5 -1
- data/lib/generators/ruby_ui/dependencies.yml +10 -0
- data/lib/generators/ruby_ui/install/docs_generator.rb +33 -0
- data/lib/generators/ruby_ui/install/install_generator.rb +1 -1
- data/lib/generators/ruby_ui/javascript_utils.rb +4 -0
- data/lib/ruby_ui/accordion/accordion_docs.rb +53 -0
- data/lib/ruby_ui/alert/alert_docs.rb +135 -0
- data/lib/ruby_ui/alert_dialog/alert_dialog_docs.rb +35 -0
- data/lib/ruby_ui/aspect_ratio/aspect_ratio_docs.rb +64 -0
- data/lib/ruby_ui/avatar/avatar_docs.rb +92 -0
- data/lib/ruby_ui/badge/badge_docs.rb +80 -0
- data/lib/ruby_ui/breadcrumb/breadcrumb_docs.rb +116 -0
- data/lib/ruby_ui/button/button_docs.rb +143 -0
- data/lib/ruby_ui/calendar/calendar_docs.rb +34 -0
- data/lib/ruby_ui/card/card_docs.rb +114 -0
- data/lib/ruby_ui/carousel/carousel_docs.rb +104 -0
- data/lib/ruby_ui/chart/chart_docs.rb +115 -0
- data/lib/ruby_ui/checkbox/checkbox.rb +2 -2
- data/lib/ruby_ui/checkbox/checkbox_docs.rb +41 -0
- data/lib/ruby_ui/clipboard/clipboard_docs.rb +30 -0
- data/lib/ruby_ui/codeblock/codeblock_docs.rb +55 -0
- data/lib/ruby_ui/collapsible/collapsible_docs.rb +96 -0
- data/lib/ruby_ui/combobox/combobox.rb +7 -1
- data/lib/ruby_ui/combobox/combobox_badge.rb +17 -0
- data/lib/ruby_ui/combobox/combobox_badge_trigger.rb +47 -0
- data/lib/ruby_ui/combobox/combobox_checkbox.rb +1 -7
- data/lib/ruby_ui/combobox/combobox_clear_button.rb +40 -0
- data/lib/ruby_ui/combobox/combobox_controller.js +252 -47
- data/lib/ruby_ui/combobox/combobox_docs.rb +286 -0
- data/lib/ruby_ui/combobox/combobox_input_trigger.rb +64 -0
- data/lib/ruby_ui/combobox/combobox_item.rb +5 -7
- data/lib/ruby_ui/combobox/combobox_item_indicator.rb +30 -0
- data/lib/ruby_ui/combobox/combobox_list_group.rb +1 -1
- data/lib/ruby_ui/combobox/combobox_popover.rb +1 -5
- data/lib/ruby_ui/combobox/combobox_radio.rb +1 -8
- data/lib/ruby_ui/combobox/combobox_toggle_all_checkbox.rb +1 -6
- data/lib/ruby_ui/combobox/combobox_trigger.rb +19 -19
- data/lib/ruby_ui/command/command_docs.rb +154 -0
- data/lib/ruby_ui/context_menu/context_menu.rb +1 -1
- data/lib/ruby_ui/context_menu/context_menu_docs.rb +85 -0
- data/lib/ruby_ui/data_table/data_table.rb +29 -0
- data/lib/ruby_ui/data_table/data_table_bulk_actions.rb +18 -0
- data/lib/ruby_ui/data_table/data_table_column_toggle.rb +62 -0
- data/lib/ruby_ui/data_table/data_table_column_visibility_controller.js +14 -0
- data/lib/ruby_ui/data_table/data_table_controller.js +57 -0
- data/lib/ruby_ui/data_table/data_table_docs.rb +180 -0
- data/lib/ruby_ui/data_table/data_table_expand_toggle.rb +53 -0
- data/lib/ruby_ui/data_table/data_table_form.rb +39 -0
- data/lib/ruby_ui/data_table/data_table_kaminari_adapter.rb +17 -0
- data/lib/ruby_ui/data_table/data_table_manual_adapter.rb +17 -0
- data/lib/ruby_ui/data_table/data_table_pagination.rb +100 -0
- data/lib/ruby_ui/data_table/data_table_pagination_bar.rb +15 -0
- data/lib/ruby_ui/data_table/data_table_pagy_adapter.rb +17 -0
- data/lib/ruby_ui/data_table/data_table_per_page_select.rb +35 -0
- data/lib/ruby_ui/data_table/data_table_row_checkbox.rb +30 -0
- data/lib/ruby_ui/data_table/data_table_search.rb +57 -0
- data/lib/ruby_ui/data_table/data_table_search_controller.js +62 -0
- data/lib/ruby_ui/data_table/data_table_select_all_checkbox.rb +21 -0
- data/lib/ruby_ui/data_table/data_table_selection_summary.rb +25 -0
- data/lib/ruby_ui/data_table/data_table_sort_head.rb +112 -0
- data/lib/ruby_ui/data_table/data_table_toolbar.rb +15 -0
- data/lib/ruby_ui/dialog/dialog_docs.rb +102 -0
- data/lib/ruby_ui/docs/base.rb +90 -0
- data/lib/ruby_ui/docs/component_setup_tabs.rb +15 -0
- data/lib/ruby_ui/docs/components_table.rb +13 -0
- data/lib/ruby_ui/docs/header.rb +17 -0
- data/lib/ruby_ui/docs/sidebar_examples.rb +22 -0
- data/lib/ruby_ui/docs/visual_code_example.rb +22 -0
- data/lib/ruby_ui/dropdown_menu/dropdown_menu_docs.rb +212 -0
- data/lib/ruby_ui/form/form_docs.rb +178 -0
- data/lib/ruby_ui/form/form_field.rb +1 -1
- data/lib/ruby_ui/form/form_field_error.rb +1 -1
- data/lib/ruby_ui/form/form_field_hint.rb +1 -1
- data/lib/ruby_ui/form/form_field_label.rb +1 -1
- data/lib/ruby_ui/hover_card/hover_card_docs.rb +71 -0
- data/lib/ruby_ui/input/input.rb +4 -3
- data/lib/ruby_ui/input/input_docs.rb +68 -0
- data/lib/ruby_ui/link/link_docs.rb +106 -0
- data/lib/ruby_ui/masked_input/masked_input.rb +11 -1
- data/lib/ruby_ui/masked_input/masked_input_controller.js +13 -0
- data/lib/ruby_ui/masked_input/masked_input_docs.rb +47 -0
- data/lib/ruby_ui/native_select/native_select.rb +39 -0
- data/lib/ruby_ui/native_select/native_select_docs.rb +83 -0
- data/lib/ruby_ui/native_select/native_select_group.rb +15 -0
- data/lib/ruby_ui/native_select/native_select_icon.rb +39 -0
- data/lib/ruby_ui/native_select/native_select_option.rb +15 -0
- data/lib/ruby_ui/pagination/pagination_docs.rb +127 -0
- data/lib/ruby_ui/popover/popover_docs.rb +971 -0
- data/lib/ruby_ui/progress/progress_docs.rb +27 -0
- data/lib/ruby_ui/radio_button/radio_button.rb +1 -1
- data/lib/ruby_ui/radio_button/radio_button_docs.rb +53 -0
- data/lib/ruby_ui/select/select_docs.rb +129 -0
- data/lib/ruby_ui/separator/separator_docs.rb +36 -0
- data/lib/ruby_ui/sheet/sheet_content.rb +1 -1
- data/lib/ruby_ui/sheet/sheet_docs.rb +76 -0
- data/lib/ruby_ui/shortcut_key/shortcut_key_docs.rb +29 -0
- data/lib/ruby_ui/sidebar/sidebar_docs.rb +176 -0
- data/lib/ruby_ui/skeleton/skeleton_docs.rb +29 -0
- data/lib/ruby_ui/switch/switch_docs.rb +46 -0
- data/lib/ruby_ui/table/table_docs.rb +102 -0
- data/lib/ruby_ui/tabs/tabs_docs.rb +211 -0
- data/lib/ruby_ui/textarea/textarea_docs.rb +54 -0
- data/lib/ruby_ui/theme_toggle/theme_toggle_docs.rb +71 -0
- data/lib/ruby_ui/tooltip/tooltip_docs.rb +52 -0
- data/lib/ruby_ui/typography/typography_docs.rb +107 -0
- data/lib/ruby_ui.rb +1 -1
- metadata +90 -3
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "cgi"
|
|
4
|
+
|
|
5
|
+
module RubyUI
|
|
6
|
+
class DataTableSortHead < Base
|
|
7
|
+
def initialize(column_key:, label:, sort: nil, direction: nil, sort_param: "sort", direction_param: "direction", page_param: "page", path: "", query: {}, **attrs)
|
|
8
|
+
@column_key = column_key
|
|
9
|
+
@label = label
|
|
10
|
+
@sort = sort
|
|
11
|
+
@direction = direction
|
|
12
|
+
@sort_param = sort_param
|
|
13
|
+
@direction_param = direction_param
|
|
14
|
+
@page_param = page_param
|
|
15
|
+
@path = path
|
|
16
|
+
@query = query.to_h.transform_keys(&:to_s)
|
|
17
|
+
super(**attrs)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def view_template
|
|
21
|
+
render RubyUI::TableHead.new(class: "text-foreground whitespace-nowrap", **attrs) do
|
|
22
|
+
a(href: sort_href, class: "inline-flex items-center gap-1 text-inherit no-underline hover:text-foreground transition-colors") do
|
|
23
|
+
plain @label
|
|
24
|
+
sort_icon
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def current_direction
|
|
32
|
+
(@sort.to_s == @column_key.to_s) ? @direction : nil
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def next_params
|
|
36
|
+
next_dir = {nil => "asc", "asc" => "desc", "desc" => nil}[current_direction]
|
|
37
|
+
base = @query.except(@sort_param, @direction_param, @page_param)
|
|
38
|
+
next_dir ? base.merge(@sort_param => @column_key.to_s, @direction_param => next_dir) : base
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def sort_href
|
|
42
|
+
qs = build_query(next_params)
|
|
43
|
+
qs.empty? ? @path : "#{@path}?#{qs}"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def build_query(hash)
|
|
47
|
+
hash.flat_map { |k, v|
|
|
48
|
+
Array(v).map { |val| "#{CGI.escape(k.to_s)}=#{CGI.escape(val.to_s)}" }
|
|
49
|
+
}.join("&")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def sort_icon
|
|
53
|
+
icon_name = case current_direction
|
|
54
|
+
when "asc" then :chevron_up
|
|
55
|
+
when "desc" then :chevron_down
|
|
56
|
+
else :chevrons_up_down
|
|
57
|
+
end
|
|
58
|
+
icon_class = current_direction ? "inline-block w-3 h-3" : "inline-block w-3 h-3 opacity-30"
|
|
59
|
+
render_sort_svg(icon_name, icon_class)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def render_sort_svg(icon_name, icon_class)
|
|
63
|
+
case icon_name
|
|
64
|
+
when :chevron_up
|
|
65
|
+
# chevron-up: polyline pointing up
|
|
66
|
+
svg(
|
|
67
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
68
|
+
width: "12",
|
|
69
|
+
height: "12",
|
|
70
|
+
viewBox: "0 0 24 24",
|
|
71
|
+
fill: "none",
|
|
72
|
+
stroke: "currentColor",
|
|
73
|
+
stroke_width: "2",
|
|
74
|
+
stroke_linecap: "round",
|
|
75
|
+
stroke_linejoin: "round",
|
|
76
|
+
class: icon_class
|
|
77
|
+
) { |s| s.polyline(points: "18 15 12 9 6 15") }
|
|
78
|
+
when :chevron_down
|
|
79
|
+
# chevron-down: polyline pointing down
|
|
80
|
+
svg(
|
|
81
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
82
|
+
width: "12",
|
|
83
|
+
height: "12",
|
|
84
|
+
viewBox: "0 0 24 24",
|
|
85
|
+
fill: "none",
|
|
86
|
+
stroke: "currentColor",
|
|
87
|
+
stroke_width: "2",
|
|
88
|
+
stroke_linecap: "round",
|
|
89
|
+
stroke_linejoin: "round",
|
|
90
|
+
class: icon_class
|
|
91
|
+
) { |s| s.polyline(points: "6 9 12 15 18 9") }
|
|
92
|
+
else
|
|
93
|
+
# chevrons-up-down
|
|
94
|
+
svg(
|
|
95
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
96
|
+
width: "12",
|
|
97
|
+
height: "12",
|
|
98
|
+
viewBox: "0 0 24 24",
|
|
99
|
+
fill: "none",
|
|
100
|
+
stroke: "currentColor",
|
|
101
|
+
stroke_width: "2",
|
|
102
|
+
stroke_linecap: "round",
|
|
103
|
+
stroke_linejoin: "round",
|
|
104
|
+
class: icon_class
|
|
105
|
+
) do |s|
|
|
106
|
+
s.polyline(points: "8 15 12 19 16 15")
|
|
107
|
+
s.polyline(points: "8 9 12 5 16 9")
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Views::Docs::Dialog < Views::Base
|
|
4
|
+
def view_template
|
|
5
|
+
component = "Dialog"
|
|
6
|
+
|
|
7
|
+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
|
|
8
|
+
render Docs::Header.new(title: "Dialog", description: "A window overlaid on either the primary window or another dialog window, rendering the content underneath inert.")
|
|
9
|
+
|
|
10
|
+
Heading(level: 2) { "Usage" }
|
|
11
|
+
|
|
12
|
+
render Docs::VisualCodeExample.new(title: "Example", context: self) do
|
|
13
|
+
<<~RUBY
|
|
14
|
+
Dialog do
|
|
15
|
+
DialogTrigger do
|
|
16
|
+
Button { "Open Dialog" }
|
|
17
|
+
end
|
|
18
|
+
DialogContent do
|
|
19
|
+
DialogHeader do
|
|
20
|
+
DialogTitle { "RubyUI to the rescue" }
|
|
21
|
+
DialogDescription { "RubyUI helps you build accessible standard compliant web apps with ease" }
|
|
22
|
+
end
|
|
23
|
+
DialogMiddle do
|
|
24
|
+
AspectRatio(aspect_ratio: "16/9", class: 'rounded-md overflow-hidden border') do
|
|
25
|
+
img(
|
|
26
|
+
alt: "Placeholder",
|
|
27
|
+
loading: "lazy",
|
|
28
|
+
src: image_path("pattern.jpg")
|
|
29
|
+
)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
DialogFooter do
|
|
33
|
+
Button(variant: :outline, data: { action: 'click->ruby-ui--dialog#dismiss' }) { "Cancel" }
|
|
34
|
+
Button { "Save" }
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
RUBY
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
render Docs::VisualCodeExample.new(title: "Size", description: "Applicable for wider screens", context: self) do
|
|
42
|
+
<<~RUBY
|
|
43
|
+
div(class: 'flex flex-wrap justify-center gap-2') do
|
|
44
|
+
Dialog do
|
|
45
|
+
DialogTrigger do
|
|
46
|
+
Button { "Small Dialog" }
|
|
47
|
+
end
|
|
48
|
+
DialogContent(size: :sm) do
|
|
49
|
+
DialogHeader do
|
|
50
|
+
DialogTitle { "RubyUI to the rescue" }
|
|
51
|
+
DialogDescription { "RubyUI helps you build accessible standard compliant web apps with ease" }
|
|
52
|
+
end
|
|
53
|
+
DialogMiddle do
|
|
54
|
+
AspectRatio(aspect_ratio: "16/9", class: 'rounded-md overflow-hidden border') do
|
|
55
|
+
img(
|
|
56
|
+
alt: "Placeholder",
|
|
57
|
+
loading: "lazy",
|
|
58
|
+
src: image_path("pattern.jpg")
|
|
59
|
+
)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
DialogFooter do
|
|
63
|
+
Button(variant: :outline, data: { action: 'click->ruby-ui--dialog#dismiss' }) { "Cancel" }
|
|
64
|
+
Button { "Save" }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
Dialog do
|
|
70
|
+
DialogTrigger do
|
|
71
|
+
Button { "Large Dialog" }
|
|
72
|
+
end
|
|
73
|
+
DialogContent(size: :lg) do
|
|
74
|
+
DialogHeader do
|
|
75
|
+
DialogTitle { "RubyUI to the rescue" }
|
|
76
|
+
DialogDescription { "RubyUI helps you build accessible standard compliant web apps with ease" }
|
|
77
|
+
end
|
|
78
|
+
DialogMiddle do
|
|
79
|
+
AspectRatio(aspect_ratio: "16/9", class: 'rounded-md overflow-hidden border') do
|
|
80
|
+
img(
|
|
81
|
+
alt: "Placeholder",
|
|
82
|
+
loading: "lazy",
|
|
83
|
+
src: image_path("pattern.jpg")
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
DialogFooter do
|
|
88
|
+
Button(variant: :outline, data: { action: 'click->ruby-ui--dialog#dismiss' }) { "Cancel" }
|
|
89
|
+
Button { "Save" }
|
|
90
|
+
end
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
RUBY
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
render Components::ComponentSetup::Tabs.new(component_name: component)
|
|
98
|
+
|
|
99
|
+
render Docs::ComponentsTable.new(component_files(component))
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Views
|
|
4
|
+
class Base < Phlex::HTML
|
|
5
|
+
def Heading(level:, &)
|
|
6
|
+
tag = :"h#{level}"
|
|
7
|
+
send(tag, &)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def component_files(component_name)
|
|
11
|
+
[]
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Text helper for wrapping paragraphs
|
|
15
|
+
def Text(&)
|
|
16
|
+
p(&)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# InlineLink helper for documentation links
|
|
20
|
+
def InlineLink(href:, target: nil, class: nil, &)
|
|
21
|
+
a(href: href, target: target, class: binding.local_variable_get(:class), &)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Alert component helpers
|
|
25
|
+
def Alert(&)
|
|
26
|
+
div(&)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def AlertTitle(&)
|
|
30
|
+
h4(&)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def AlertDescription(&)
|
|
34
|
+
p(&)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Route helper stubs - return "#" as placeholder
|
|
38
|
+
def docs_sheet_path
|
|
39
|
+
"#"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def docs_separator_path
|
|
43
|
+
"#"
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def docs_accordion_path
|
|
47
|
+
"#"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def docs_alert_path
|
|
51
|
+
"#"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def docs_alert_dialog_path
|
|
55
|
+
"#"
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def docs_aspect_ratio_path
|
|
59
|
+
"#"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def docs_avatar_path
|
|
63
|
+
"#"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def docs_badge_path
|
|
67
|
+
"#"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def docs_installation_path
|
|
71
|
+
"#"
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# InlineCode helper for typography examples
|
|
75
|
+
def InlineCode(&)
|
|
76
|
+
code(&)
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Module-level components stub
|
|
82
|
+
module Components
|
|
83
|
+
def self.Heading(level:, &block)
|
|
84
|
+
# Stub for module-level Heading calls
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def self.TypographyList(items:, numbered: false)
|
|
88
|
+
# Stub for TypographyList component
|
|
89
|
+
end
|
|
90
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Components
|
|
4
|
+
module ComponentSetup
|
|
5
|
+
class Tabs < Phlex::HTML
|
|
6
|
+
def initialize(component_name:)
|
|
7
|
+
@component_name = component_name
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template
|
|
11
|
+
# Minimal stub - empty by default
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Docs
|
|
4
|
+
class Header < Phlex::HTML
|
|
5
|
+
def initialize(title:, description: nil)
|
|
6
|
+
@title = title
|
|
7
|
+
@description = description
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template
|
|
11
|
+
div do
|
|
12
|
+
h1 { @title }
|
|
13
|
+
p { @description } if @description
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Stub constants for sidebar documentation examples
|
|
4
|
+
# These are replaced with actual implementations in the web app
|
|
5
|
+
|
|
6
|
+
module Views
|
|
7
|
+
module Docs
|
|
8
|
+
class Sidebar < Views::Base
|
|
9
|
+
class Example
|
|
10
|
+
CODE = <<~RUBY
|
|
11
|
+
# Sidebar example code placeholder
|
|
12
|
+
RUBY
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class InsetExample
|
|
16
|
+
CODE = <<~RUBY
|
|
17
|
+
# Sidebar inset example code placeholder
|
|
18
|
+
RUBY
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Docs
|
|
4
|
+
class VisualCodeExample < Phlex::HTML
|
|
5
|
+
def initialize(title:, context:, description: nil, src: nil)
|
|
6
|
+
@title = title
|
|
7
|
+
@context = context
|
|
8
|
+
@description = description
|
|
9
|
+
@src = src
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def view_template(&block)
|
|
13
|
+
code = block.call
|
|
14
|
+
div do
|
|
15
|
+
h3 { @title }
|
|
16
|
+
p { @description } if @description
|
|
17
|
+
pre { code }
|
|
18
|
+
@context.instance_eval(code)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Views::Docs::DropdownMenu < Views::Base
|
|
4
|
+
def view_template
|
|
5
|
+
component = "DropdownMenu"
|
|
6
|
+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
|
|
7
|
+
render Docs::Header.new(title: "Dropdown Menu", description: "Displays a menu to the user — such as a set of actions or functions — triggered by a button.")
|
|
8
|
+
|
|
9
|
+
Heading(level: 2) { "Usage" }
|
|
10
|
+
|
|
11
|
+
render Docs::VisualCodeExample.new(title: "Example", context: self) do
|
|
12
|
+
<<~RUBY
|
|
13
|
+
DropdownMenu do
|
|
14
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
15
|
+
Button(variant: :outline) { "Open" }
|
|
16
|
+
end
|
|
17
|
+
DropdownMenuContent do
|
|
18
|
+
DropdownMenuLabel { "My Account" }
|
|
19
|
+
DropdownMenuSeparator
|
|
20
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
21
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
22
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
23
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
RUBY
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
render Docs::VisualCodeExample.new(title: "Placement", description: "If the DropdownMenu conflicts with edge, it will auto-adjust it's placement", context: self) do
|
|
30
|
+
<<~RUBY
|
|
31
|
+
div(class: 'grid grid-cols-1 sm:grid-cols-3 gap-4') do
|
|
32
|
+
# -- TOP --
|
|
33
|
+
DropdownMenu(options: { placement: 'top' }) do
|
|
34
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
35
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'top' }
|
|
36
|
+
end
|
|
37
|
+
DropdownMenuContent do
|
|
38
|
+
DropdownMenuLabel { "My Account" }
|
|
39
|
+
DropdownMenuSeparator
|
|
40
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
41
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
42
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
43
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
DropdownMenu(options: { placement: 'top-start' }) do
|
|
48
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
49
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'top-start' }
|
|
50
|
+
end
|
|
51
|
+
DropdownMenuContent do
|
|
52
|
+
DropdownMenuLabel { "My Account" }
|
|
53
|
+
DropdownMenuSeparator
|
|
54
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
55
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
56
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
57
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
DropdownMenu(options: { placement: 'top-end' }) do
|
|
62
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
63
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'top-end' }
|
|
64
|
+
end
|
|
65
|
+
DropdownMenuContent do
|
|
66
|
+
DropdownMenuLabel { "My Account" }
|
|
67
|
+
DropdownMenuSeparator
|
|
68
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
69
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
70
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
71
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# -- BOTTOM --
|
|
76
|
+
DropdownMenu(options: { placement: 'bottom' }) do
|
|
77
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
78
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'bottom' }
|
|
79
|
+
end
|
|
80
|
+
DropdownMenuContent do
|
|
81
|
+
DropdownMenuLabel { "My Account" }
|
|
82
|
+
DropdownMenuSeparator
|
|
83
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
84
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
85
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
86
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
DropdownMenu(options: { placement: 'bottom-start' }) do
|
|
91
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
92
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'bottom-start' }
|
|
93
|
+
end
|
|
94
|
+
DropdownMenuContent do
|
|
95
|
+
DropdownMenuLabel { "My Account" }
|
|
96
|
+
DropdownMenuSeparator
|
|
97
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
98
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
99
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
100
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
DropdownMenu(options: { placement: 'bottom-end' }) do
|
|
105
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
106
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'bottom-end' }
|
|
107
|
+
end
|
|
108
|
+
DropdownMenuContent do
|
|
109
|
+
DropdownMenuLabel { "My Account" }
|
|
110
|
+
DropdownMenuSeparator
|
|
111
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
112
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
113
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
114
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# -- LEFT --
|
|
119
|
+
DropdownMenu(options: { placement: 'left' }) do
|
|
120
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
121
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'left' }
|
|
122
|
+
end
|
|
123
|
+
DropdownMenuContent do
|
|
124
|
+
DropdownMenuLabel { "My Account" }
|
|
125
|
+
DropdownMenuSeparator
|
|
126
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
127
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
128
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
129
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
DropdownMenu(options: { placement: 'left-start' }) do
|
|
134
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
135
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'left-start' }
|
|
136
|
+
end
|
|
137
|
+
DropdownMenuContent do
|
|
138
|
+
DropdownMenuLabel { "My Account" }
|
|
139
|
+
DropdownMenuSeparator
|
|
140
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
141
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
142
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
143
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
DropdownMenu(options: { placement: 'left-end' }) do
|
|
148
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
149
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'left-end' }
|
|
150
|
+
end
|
|
151
|
+
DropdownMenuContent do
|
|
152
|
+
DropdownMenuLabel { "My Account" }
|
|
153
|
+
DropdownMenuSeparator
|
|
154
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
155
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
156
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
157
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# -- RIGHT --
|
|
162
|
+
DropdownMenu(options: { placement: 'right' }) do
|
|
163
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
164
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'right' }
|
|
165
|
+
end
|
|
166
|
+
DropdownMenuContent do
|
|
167
|
+
DropdownMenuLabel { "My Account" }
|
|
168
|
+
DropdownMenuSeparator
|
|
169
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
170
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
171
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
172
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
DropdownMenu(options: { placement: 'right-start' }) do
|
|
177
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
178
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'right-start' }
|
|
179
|
+
end
|
|
180
|
+
DropdownMenuContent do
|
|
181
|
+
DropdownMenuLabel { "My Account" }
|
|
182
|
+
DropdownMenuSeparator
|
|
183
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
184
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
185
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
186
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
187
|
+
end
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
DropdownMenu(options: { placement: 'right-end' }) do
|
|
191
|
+
DropdownMenuTrigger(class: 'w-full') do
|
|
192
|
+
Button(variant: :outline, class: 'w-full justify-center') { 'right-end' }
|
|
193
|
+
end
|
|
194
|
+
DropdownMenuContent do
|
|
195
|
+
DropdownMenuLabel { "My Account" }
|
|
196
|
+
DropdownMenuSeparator
|
|
197
|
+
DropdownMenuItem(href: '#') { "Profile" }
|
|
198
|
+
DropdownMenuItem(href: '#') { "Billing" }
|
|
199
|
+
DropdownMenuItem(href: '#') { "Team" }
|
|
200
|
+
DropdownMenuItem(href: '#') { "Subscription" }
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
RUBY
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
render Components::ComponentSetup::Tabs.new(component_name: component)
|
|
208
|
+
|
|
209
|
+
render Docs::ComponentsTable.new(component_files(component))
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|