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.
- checksums.yaml +4 -4
- data/LICENSE.txt +1 -1
- data/README.md +6 -0
- data/lib/generators/ruby_ui/component/all_generator.rb +22 -0
- data/lib/generators/ruby_ui/component_generator.rb +4 -3
- data/lib/generators/ruby_ui/install/docs_generator.rb +33 -0
- data/lib/generators/ruby_ui/install/install_generator.rb +1 -7
- data/lib/generators/ruby_ui/install/templates/tailwind.css.erb +0 -3
- 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_content.rb +2 -3
- 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.rb +32 -16
- 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 +7 -1
- 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 +3 -2
- data/lib/ruby_ui/combobox/combobox_checkbox.rb +4 -2
- data/lib/ruby_ui/combobox/combobox_controller.js +20 -5
- data/lib/ruby_ui/combobox/combobox_docs.rb +151 -0
- data/lib/ruby_ui/combobox/combobox_item.rb +2 -1
- data/lib/ruby_ui/combobox/combobox_popover.rb +2 -1
- data/lib/ruby_ui/combobox/combobox_radio.rb +8 -1
- data/lib/ruby_ui/combobox/combobox_search_input.rb +11 -5
- data/lib/ruby_ui/combobox/combobox_toggle_all_checkbox.rb +4 -2
- data/lib/ruby_ui/combobox/combobox_trigger.rb +8 -2
- data/lib/ruby_ui/command/command_controller.js +0 -1
- 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/dialog/dialog_content.rb +2 -3
- data/lib/ruby_ui/dialog/dialog_controller.js +1 -1
- 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.rb +9 -0
- data/lib/ruby_ui/dropdown_menu/dropdown_menu_content.rb +17 -2
- data/lib/ruby_ui/dropdown_menu/dropdown_menu_controller.js +43 -14
- 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 +7 -1
- data/lib/ruby_ui/hover_card/hover_card_docs.rb +71 -0
- data/lib/ruby_ui/input/input.rb +9 -1
- data/lib/ruby_ui/input/input_docs.rb +68 -0
- data/lib/ruby_ui/link/link.rb +32 -16
- data/lib/ruby_ui/link/link_docs.rb +106 -0
- data/lib/ruby_ui/masked_input/masked_input_docs.rb +47 -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 +3 -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/select/select_item.rb +14 -5
- data/lib/ruby_ui/select/select_trigger.rb +9 -4
- 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/collapsible_sidebar.rb +99 -0
- data/lib/ruby_ui/sidebar/mobile_sidebar.rb +45 -0
- data/lib/ruby_ui/sidebar/non_collapsible_sidebar.rb +17 -0
- data/lib/ruby_ui/sidebar/sidebar.rb +29 -0
- data/lib/ruby_ui/sidebar/sidebar_content.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_controller.js +67 -0
- data/lib/ruby_ui/sidebar/sidebar_docs.rb +176 -0
- data/lib/ruby_ui/sidebar/sidebar_footer.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_group.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_group_action.rb +33 -0
- data/lib/ruby_ui/sidebar/sidebar_group_content.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_group_label.rb +26 -0
- data/lib/ruby_ui/sidebar/sidebar_header.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_input.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_inset.rb +23 -0
- data/lib/ruby_ui/sidebar/sidebar_menu.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_action.rb +48 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_badge.rb +30 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_button.rb +63 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_item.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_skeleton.rb +36 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_sub.rb +24 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_sub_button.rb +50 -0
- data/lib/ruby_ui/sidebar/sidebar_menu_sub_item.rb +9 -0
- data/lib/ruby_ui/sidebar/sidebar_rail.rb +36 -0
- data/lib/ruby_ui/sidebar/sidebar_separator.rb +20 -0
- data/lib/ruby_ui/sidebar/sidebar_trigger.rb +42 -0
- data/lib/ruby_ui/sidebar/sidebar_wrapper.rb +24 -0
- data/lib/ruby_ui/skeleton/skeleton_docs.rb +29 -0
- data/lib/ruby_ui/switch/switch.rb +12 -2
- data/lib/ruby_ui/switch/switch_docs.rb +46 -0
- data/lib/ruby_ui/table/table_docs.rb +102 -0
- data/lib/ruby_ui/table/table_footer.rb +1 -1
- data/lib/ruby_ui/table/table_row.rb +1 -1
- data/lib/ruby_ui/tabs/tabs_docs.rb +211 -0
- data/lib/ruby_ui/tabs/tabs_trigger.rb +7 -1
- data/lib/ruby_ui/textarea/textarea.rb +8 -1
- 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_controller.js +5 -4
- 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 +81 -6
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
|
2
|
+
|
|
3
|
+
const SIDEBAR_COOKIE_NAME = "sidebar_state";
|
|
4
|
+
const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
|
|
5
|
+
const State = {
|
|
6
|
+
EXPANDED: "expanded",
|
|
7
|
+
COLLAPSED: "collapsed",
|
|
8
|
+
};
|
|
9
|
+
const MOBILE_BREAKPOINT = 768;
|
|
10
|
+
|
|
11
|
+
export default class extends Controller {
|
|
12
|
+
static targets = ["sidebar", "mobileSidebar"];
|
|
13
|
+
|
|
14
|
+
sidebarTargetConnected() {
|
|
15
|
+
const { state, collapsibleKind } = this.sidebarTarget.dataset;
|
|
16
|
+
|
|
17
|
+
this.open = state === State.EXPANDED;
|
|
18
|
+
this.collapsibleKind = collapsibleKind;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
toggle(e) {
|
|
22
|
+
e.preventDefault();
|
|
23
|
+
|
|
24
|
+
if (this.#isMobile()) {
|
|
25
|
+
this.#openMobileSidebar();
|
|
26
|
+
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
this.open = !this.open;
|
|
31
|
+
this.onToggle();
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
onToggle() {
|
|
35
|
+
this.#updateSidebarState();
|
|
36
|
+
this.#persistSidebarState();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
#updateSidebarState() {
|
|
40
|
+
if (!this.hasSidebarTarget) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const { dataset } = this.sidebarTarget;
|
|
45
|
+
|
|
46
|
+
dataset.state = this.open ? State.EXPANDED : State.COLLAPSED;
|
|
47
|
+
dataset.collapsible = this.open ? "" : this.collapsibleKind;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#persistSidebarState() {
|
|
51
|
+
document.cookie = `${SIDEBAR_COOKIE_NAME}=${this.open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
#isMobile() {
|
|
55
|
+
return window.innerWidth < MOBILE_BREAKPOINT;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
#openMobileSidebar() {
|
|
59
|
+
if (!this.hasMobileSidebarTarget) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
this.mobileSidebarTarget.dispatchEvent(
|
|
64
|
+
new CustomEvent("ruby--ui-sidebar:open"),
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class Views::Docs::Sidebar < Views::Base
|
|
4
|
+
def view_template
|
|
5
|
+
component = "Sidebar"
|
|
6
|
+
|
|
7
|
+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
|
|
8
|
+
render Docs::Header.new(title: "Sidebar", description: "A composable, themeable and customizable sidebar component.")
|
|
9
|
+
|
|
10
|
+
Heading(level: 2) { "Usage" }
|
|
11
|
+
|
|
12
|
+
Alert do
|
|
13
|
+
info_icon
|
|
14
|
+
AlertTitle { "Requirements" }
|
|
15
|
+
AlertDescription { "The sidebar component depends on the following components:" }
|
|
16
|
+
ul(class: "list-disc list-inside") do
|
|
17
|
+
li do
|
|
18
|
+
InlineLink(href: docs_sheet_path, target: "_blank", class: "inline-flex items-center gap-2") do
|
|
19
|
+
span { "Sheet" }
|
|
20
|
+
external_icon_link
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
li do
|
|
24
|
+
div(class: "inline-flex items-center gap-2") do
|
|
25
|
+
InlineLink(href: docs_separator_path, target: "_blank") { "Separator" }
|
|
26
|
+
external_icon_link
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
render Docs::VisualCodeExample.new(title: "Example", src: "/docs/sidebar/example", context: self) do
|
|
33
|
+
Views::Docs::Sidebar::Example::CODE
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
render Docs::VisualCodeExample.new(title: "Inset variant", src: "/docs/sidebar/inset", context: self) do
|
|
37
|
+
Views::Docs::Sidebar::InsetExample::CODE
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
render Docs::VisualCodeExample.new(title: "Dialog variant", context: self) do
|
|
41
|
+
<<~RUBY
|
|
42
|
+
Dialog(data: {action: "ruby-ui--dialog:connect->ruby-ui--dialog#open"}) do
|
|
43
|
+
DialogTrigger do
|
|
44
|
+
Button { "Open Dialog" }
|
|
45
|
+
end
|
|
46
|
+
DialogContent(class: "grid overflow-hidden p-0 md:max-h-[500px] md:max-w-[700px] lg:max-w-[800px]") do
|
|
47
|
+
SidebarWrapper(class: "items-start") do
|
|
48
|
+
Sidebar(collapsible: :none, class: "hidden md:flex") do
|
|
49
|
+
SidebarContent do
|
|
50
|
+
SidebarGroup do
|
|
51
|
+
SidebarGroupContent do
|
|
52
|
+
SidebarMenu do
|
|
53
|
+
SidebarMenuItem do
|
|
54
|
+
SidebarMenuButton(as: :a, href: "#") do
|
|
55
|
+
search_icon()
|
|
56
|
+
span { "Search" }
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
SidebarMenuItem do
|
|
60
|
+
SidebarMenuButton(as: :a, href: "#", active: true) do
|
|
61
|
+
home_icon()
|
|
62
|
+
span { "Home" }
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
SidebarMenuItem do
|
|
66
|
+
SidebarMenuButton(as: :a, href: "#") do
|
|
67
|
+
inbox_icon()
|
|
68
|
+
span { "Inbox" }
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
main(class: "flex h-[480px] flex-1 flex-col overflow-hidden") do
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
RUBY
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
render Components::ComponentSetup::Tabs.new(component_name: component)
|
|
85
|
+
|
|
86
|
+
render Docs::ComponentsTable.new(component_files(component))
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def search_icon
|
|
91
|
+
svg(
|
|
92
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
93
|
+
width: "24",
|
|
94
|
+
height: "24",
|
|
95
|
+
viewBox: "0 0 24 24",
|
|
96
|
+
fill: "none",
|
|
97
|
+
stroke: "currentColor",
|
|
98
|
+
stroke_width: "2",
|
|
99
|
+
stroke_linecap: "round",
|
|
100
|
+
stroke_linejoin: "round",
|
|
101
|
+
class: "lucide lucide-search"
|
|
102
|
+
) do |s|
|
|
103
|
+
s.circle(cx: "11", cy: "11", r: "8")
|
|
104
|
+
s.path(d: "M21 21L16.7 16.7")
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def home_icon
|
|
109
|
+
svg(
|
|
110
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
111
|
+
width: "24",
|
|
112
|
+
height: "24",
|
|
113
|
+
viewBox: "0 0 24 24",
|
|
114
|
+
fill: "none",
|
|
115
|
+
stroke: "currentColor",
|
|
116
|
+
stroke_width: "2",
|
|
117
|
+
stroke_linecap: "round",
|
|
118
|
+
stroke_linejoin: "round",
|
|
119
|
+
class: "lucide lucide-house"
|
|
120
|
+
) do |s|
|
|
121
|
+
s.path(d: "M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8")
|
|
122
|
+
s.path(d: "M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z")
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def inbox_icon
|
|
127
|
+
svg(
|
|
128
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
129
|
+
width: "24",
|
|
130
|
+
height: "24",
|
|
131
|
+
viewBox: "0 0 24 24",
|
|
132
|
+
fill: "none",
|
|
133
|
+
stroke: "currentColor",
|
|
134
|
+
stroke_width: "2",
|
|
135
|
+
stroke_linecap: "round",
|
|
136
|
+
stroke_linejoin: "round",
|
|
137
|
+
class: "lucide lucide-inbox"
|
|
138
|
+
) do |s|
|
|
139
|
+
s.polyline(points: "22 12 16 12 14 15 10 15 8 12 2 12")
|
|
140
|
+
s.path(d: "M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z")
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
def external_icon_link
|
|
145
|
+
svg(
|
|
146
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
147
|
+
viewBox: "0 0 24 24",
|
|
148
|
+
fill: "none",
|
|
149
|
+
stroke: "currentColor",
|
|
150
|
+
stroke_width: "2",
|
|
151
|
+
stroke_linecap: "round",
|
|
152
|
+
stroke_linejoin: "round",
|
|
153
|
+
class: "lucide lucide-external-link-icon lucide-external-link size-3"
|
|
154
|
+
) do |s|
|
|
155
|
+
s.path(d: "M15 3h6v6")
|
|
156
|
+
s.path(d: "M10 14 21 3")
|
|
157
|
+
s.path(d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6")
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def info_icon
|
|
162
|
+
svg(
|
|
163
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
164
|
+
viewbox: "0 0 24 24",
|
|
165
|
+
fill: "currentColor",
|
|
166
|
+
class: "w-5 h-5"
|
|
167
|
+
) do |s|
|
|
168
|
+
s.path(
|
|
169
|
+
fill_rule: "evenodd",
|
|
170
|
+
d:
|
|
171
|
+
"M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zm8.706-1.442c1.146-.573 2.437.463 2.126 1.706l-.709 2.836.042-.02a.75.75 0 01.67 1.34l-.04.022c-1.147.573-2.438-.463-2.127-1.706l.71-2.836-.042.02a.75.75 0 11-.671-1.34l.041-.022zM12 9a.75.75 0 100-1.5.75.75 0 000 1.5z",
|
|
172
|
+
clip_rule: "evenodd"
|
|
173
|
+
)
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarFooter < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: "flex flex-col gap-2 p-2",
|
|
14
|
+
data: {
|
|
15
|
+
sidebar: "footer"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarGroup < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: "relative flex w-full min-w-0 flex-col p-2",
|
|
14
|
+
data: {
|
|
15
|
+
sidebar: "group"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarGroupAction < Base
|
|
5
|
+
def initialize(as: :button, **attrs)
|
|
6
|
+
@as = as
|
|
7
|
+
super(**attrs)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template(&)
|
|
11
|
+
tag(@as, **attrs, &)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def default_attrs
|
|
17
|
+
{
|
|
18
|
+
class: [
|
|
19
|
+
"absolute right-3 top-3.5 flex aspect-square w-5 items-center",
|
|
20
|
+
"justify-center rounded-md p-0 text-sidebar-foreground",
|
|
21
|
+
"outline-none ring-sidebar-ring transition-transform",
|
|
22
|
+
"hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
23
|
+
"focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
|
24
|
+
"after:absolute after:-inset-2 after:md:hidden",
|
|
25
|
+
"group-data-[collapsible=icon]:hidden"
|
|
26
|
+
],
|
|
27
|
+
data: {
|
|
28
|
+
sidebar: "group-action"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarGroupContent < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: "w-full text-sm",
|
|
14
|
+
data: {
|
|
15
|
+
sidebar: "group-content"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarGroupLabel < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: [
|
|
14
|
+
"flex h-8 shrink-0 items-center rounded-md px-2 text-xs",
|
|
15
|
+
"font-medium text-sidebar-foreground/70 outline-none",
|
|
16
|
+
"ring-sidebar-ring transition-[margin,opacity] duration-200",
|
|
17
|
+
"ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0",
|
|
18
|
+
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0"
|
|
19
|
+
],
|
|
20
|
+
data: {
|
|
21
|
+
sidebar: "group-label"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarHeader < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: "flex flex-col gap-2 p-2",
|
|
14
|
+
data: {
|
|
15
|
+
sidebar: "header"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarInput < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
Input(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: "h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring",
|
|
14
|
+
data: {
|
|
15
|
+
sidebar: "input"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarInset < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
main(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: [
|
|
14
|
+
"relative flex w-full flex-1 flex-col bg-background",
|
|
15
|
+
"md:peer-data-[variant=inset]:m-2",
|
|
16
|
+
"md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2",
|
|
17
|
+
"md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl",
|
|
18
|
+
"md:peer-data-[variant=inset]:shadow"
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarMenu < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
ul(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: "flex w-full min-w-0 flex-col gap-1",
|
|
14
|
+
data: {
|
|
15
|
+
sidebar: "menu"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarMenuAction < Base
|
|
5
|
+
def initialize(as: :button, show_on_hover: false, **attrs)
|
|
6
|
+
@as = as
|
|
7
|
+
super(**attrs)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template(&)
|
|
11
|
+
tag(@as, **attrs, &)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def default_attrs
|
|
17
|
+
{
|
|
18
|
+
class: [
|
|
19
|
+
"absolute right-1 top-1.5 flex aspect-square w-5 items-center",
|
|
20
|
+
"justify-center rounded-md p-0 text-sidebar-foreground outline-none",
|
|
21
|
+
"ring-sidebar-ring transition-transform hover:bg-sidebar-accent",
|
|
22
|
+
"hover:text-sidebar-accent-foreground focus-visible:ring-2",
|
|
23
|
+
"peer-hover/menu-button:text-sidebar-accent-foreground",
|
|
24
|
+
"[&>svg]:size-4 [&>svg]:shrink-0",
|
|
25
|
+
"after:absolute after:-inset-2 after:md:hidden",
|
|
26
|
+
"peer-data-[size=sm]/menu-button:top-1",
|
|
27
|
+
"peer-data-[size=default]/menu-button:top-1.5",
|
|
28
|
+
"peer-data-[size=lg]/menu-button:top-2.5",
|
|
29
|
+
"group-data-[collapsible=icon]:hidden",
|
|
30
|
+
show_on_hover_classes
|
|
31
|
+
],
|
|
32
|
+
data: {
|
|
33
|
+
sidebar: "menu-action"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def show_on_hover_classes
|
|
39
|
+
return unless @show_on_hover
|
|
40
|
+
|
|
41
|
+
[
|
|
42
|
+
"group-focus-within/menu-item:opacity-100",
|
|
43
|
+
"group-hover/menu-item:opacity-100 data-[state=open]:opacity-100",
|
|
44
|
+
"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground md:opacity-0"
|
|
45
|
+
].join(" ")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarMenuBadge < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: [
|
|
14
|
+
"pointer-events-none absolute right-1 flex h-5 min-w-5 select-none",
|
|
15
|
+
"items-center justify-center rounded-md px-1 text-xs font-medium",
|
|
16
|
+
"tabular-nums text-sidebar-foreground",
|
|
17
|
+
"peer-hover/menu-button:text-sidebar-accent-foreground",
|
|
18
|
+
"peer-data-[active=true]/menu-button:text-sidebar-accent-foreground",
|
|
19
|
+
"peer-data-[size=sm]/menu-button:top-1",
|
|
20
|
+
"peer-data-[size=default]/menu-button:top-1.5",
|
|
21
|
+
"peer-data-[size=lg]/menu-button:top-2.5",
|
|
22
|
+
"group-data-[collapsible=icon]:hidden"
|
|
23
|
+
],
|
|
24
|
+
data: {
|
|
25
|
+
sidebar: "menu-badge"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarMenuButton < Base
|
|
5
|
+
VARIANT_CLASSES = {
|
|
6
|
+
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
7
|
+
outline:
|
|
8
|
+
"bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]"
|
|
9
|
+
}.freeze
|
|
10
|
+
|
|
11
|
+
SIZE_CLASSES = {
|
|
12
|
+
default: "h-8 text-sm",
|
|
13
|
+
sm: "h-7 text-xs",
|
|
14
|
+
lg: "h-12 text-sm group-data-[collapsible=icon]:!p-0"
|
|
15
|
+
}.freeze
|
|
16
|
+
|
|
17
|
+
def initialize(as: :button, variant: :default, size: :default, active: false, **attrs)
|
|
18
|
+
raise ArgumentError, "Invalid variant: #{variant}" unless VARIANT_CLASSES.key?(variant)
|
|
19
|
+
raise ArgumentError, "Invalid size: #{size}" unless SIZE_CLASSES.key?(size)
|
|
20
|
+
|
|
21
|
+
@as = as
|
|
22
|
+
@variant = variant
|
|
23
|
+
@size = size
|
|
24
|
+
@active = active
|
|
25
|
+
super(**attrs)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def view_template(&)
|
|
29
|
+
tag(@as, **attrs, &)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def default_attrs
|
|
35
|
+
{
|
|
36
|
+
class: [
|
|
37
|
+
"peer/menu-button flex w-full items-center gap-2 overflow-hidden",
|
|
38
|
+
"rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring",
|
|
39
|
+
"transition-[width,height,padding] hover:bg-sidebar-accent",
|
|
40
|
+
"hover:text-sidebar-accent-foreground focus-visible:ring-2",
|
|
41
|
+
"active:bg-sidebar-accent active:text-sidebar-accent-foreground",
|
|
42
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
43
|
+
"group-has-[[data-sidebar=menu-action]]/menu-item:pr-8",
|
|
44
|
+
"aria-disabled:pointer-events-none aria-disabled:opacity-50",
|
|
45
|
+
"data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium",
|
|
46
|
+
"data-[active=true]:text-sidebar-accent-foreground",
|
|
47
|
+
"data-[state=open]:hover:bg-sidebar-accent",
|
|
48
|
+
"data-[state=open]:hover:text-sidebar-accent-foreground",
|
|
49
|
+
"group-data-[collapsible=icon]:!size-8",
|
|
50
|
+
"group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate",
|
|
51
|
+
"[&>svg]:size-4 [&>svg]:shrink-0",
|
|
52
|
+
VARIANT_CLASSES[@variant],
|
|
53
|
+
SIZE_CLASSES[@size]
|
|
54
|
+
],
|
|
55
|
+
data: {
|
|
56
|
+
sidebar: "menu-button",
|
|
57
|
+
size: @size,
|
|
58
|
+
active: @active.to_s
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarMenuItem < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
ul(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: "group/menu-item relative",
|
|
14
|
+
data: {
|
|
15
|
+
sidebar: "menu-item"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarMenuSkeleton < Base
|
|
5
|
+
def initialize(show_icon: false, **attrs)
|
|
6
|
+
@show_icon = show_icon
|
|
7
|
+
super(**attrs)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def view_template(&)
|
|
11
|
+
div(**attrs) do
|
|
12
|
+
Skeleton(class: "size-4 rounded-md", data: {sidebar: "menu-skeleton-icon"}) if @show_icon
|
|
13
|
+
Skeleton(
|
|
14
|
+
class: "h-4 max-w-[var(--skeleton-width)] flex-1",
|
|
15
|
+
data: {sidebar: "menu-skeleton-text"},
|
|
16
|
+
style: {"--skeleton-width" => "#{skeleton_width}%"}
|
|
17
|
+
)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def default_attrs
|
|
24
|
+
{
|
|
25
|
+
class: "flex h-8 items-center gap-2 rounded-md px-2",
|
|
26
|
+
data: {
|
|
27
|
+
sidebar: "menu-skeleton"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def skeleton_width
|
|
33
|
+
@_skeleton_width ||= rand(50..89)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RubyUI
|
|
4
|
+
class SidebarMenuSub < Base
|
|
5
|
+
def view_template(&)
|
|
6
|
+
ul(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: [
|
|
14
|
+
"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l",
|
|
15
|
+
"border-sidebar-border px-2.5 py-0.5",
|
|
16
|
+
"group-data-[collapsible=icon]:hidden"
|
|
17
|
+
],
|
|
18
|
+
data: {
|
|
19
|
+
sidebar: "menu-sub"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|