shadcn-phlex 0.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 +7 -0
- data/README.md +195 -0
- data/app.css +20 -0
- data/css/shadcn-source.css +3 -0
- data/css/shadcn-tailwind.css +160 -0
- data/css/themes/mauve.css +62 -0
- data/css/themes/mist.css +62 -0
- data/css/themes/neutral.css +74 -0
- data/css/themes/olive.css +62 -0
- data/css/themes/stone.css +62 -0
- data/css/themes/taupe.css +62 -0
- data/css/themes/zinc.css +62 -0
- data/js/controllers/accordion_controller.js +135 -0
- data/js/controllers/checkbox_controller.js +52 -0
- data/js/controllers/collapsible_controller.js +85 -0
- data/js/controllers/combobox_controller.js +168 -0
- data/js/controllers/command_controller.js +171 -0
- data/js/controllers/context_menu_controller.js +132 -0
- data/js/controllers/dark_mode_controller.js +106 -0
- data/js/controllers/dialog_controller.js +205 -0
- data/js/controllers/drawer_controller.js +161 -0
- data/js/controllers/dropdown_menu_controller.js +189 -0
- data/js/controllers/hover_card_controller.js +85 -0
- data/js/controllers/index.js +89 -0
- data/js/controllers/menubar_controller.js +171 -0
- data/js/controllers/navigation_menu_controller.js +160 -0
- data/js/controllers/popover_controller.js +151 -0
- data/js/controllers/radio_group_controller.js +78 -0
- data/js/controllers/scroll_area_controller.js +117 -0
- data/js/controllers/select_controller.js +198 -0
- data/js/controllers/sheet_controller.js +130 -0
- data/js/controllers/slider_controller.js +142 -0
- data/js/controllers/switch_controller.js +40 -0
- data/js/controllers/tabs_controller.js +96 -0
- data/js/controllers/toast_controller.js +206 -0
- data/js/controllers/toggle_controller.js +30 -0
- data/js/controllers/toggle_group_controller.js +73 -0
- data/js/controllers/tooltip_controller.js +146 -0
- data/lib/generators/shadcn_phlex/component_generator.rb +79 -0
- data/lib/generators/shadcn_phlex/install_generator.rb +217 -0
- data/lib/shadcn/base.rb +27 -0
- data/lib/shadcn/engine.rb +24 -0
- data/lib/shadcn/kit.rb +1158 -0
- data/lib/shadcn/themes/accent_colors.rb +106 -0
- data/lib/shadcn/themes/base_colors.rb +313 -0
- data/lib/shadcn/ui/accordion.rb +135 -0
- data/lib/shadcn/ui/alert.rb +79 -0
- data/lib/shadcn/ui/alert_dialog.rb +220 -0
- data/lib/shadcn/ui/aspect_ratio.rb +35 -0
- data/lib/shadcn/ui/avatar.rb +134 -0
- data/lib/shadcn/ui/badge.rb +48 -0
- data/lib/shadcn/ui/breadcrumb.rb +180 -0
- data/lib/shadcn/ui/button.rb +63 -0
- data/lib/shadcn/ui/button_group.rb +58 -0
- data/lib/shadcn/ui/card.rb +133 -0
- data/lib/shadcn/ui/checkbox.rb +72 -0
- data/lib/shadcn/ui/collapsible.rb +76 -0
- data/lib/shadcn/ui/combobox.rb +229 -0
- data/lib/shadcn/ui/command.rb +256 -0
- data/lib/shadcn/ui/context_menu.rb +319 -0
- data/lib/shadcn/ui/dialog.rb +226 -0
- data/lib/shadcn/ui/direction.rb +23 -0
- data/lib/shadcn/ui/drawer.rb +217 -0
- data/lib/shadcn/ui/dropdown_menu.rb +384 -0
- data/lib/shadcn/ui/empty.rb +97 -0
- data/lib/shadcn/ui/field.rb +126 -0
- data/lib/shadcn/ui/hover_card.rb +75 -0
- data/lib/shadcn/ui/input.rb +36 -0
- data/lib/shadcn/ui/input_group.rb +32 -0
- data/lib/shadcn/ui/input_otp.rb +112 -0
- data/lib/shadcn/ui/item.rb +115 -0
- data/lib/shadcn/ui/kbd.rb +45 -0
- data/lib/shadcn/ui/label.rb +28 -0
- data/lib/shadcn/ui/menubar.rb +345 -0
- data/lib/shadcn/ui/native_select.rb +31 -0
- data/lib/shadcn/ui/navigation_menu.rb +238 -0
- data/lib/shadcn/ui/pagination.rb +224 -0
- data/lib/shadcn/ui/popover.rb +147 -0
- data/lib/shadcn/ui/progress.rb +40 -0
- data/lib/shadcn/ui/radio_group.rb +92 -0
- data/lib/shadcn/ui/resizable.rb +108 -0
- data/lib/shadcn/ui/scroll_area.rb +75 -0
- data/lib/shadcn/ui/select.rb +235 -0
- data/lib/shadcn/ui/separator.rb +36 -0
- data/lib/shadcn/ui/sheet.rb +231 -0
- data/lib/shadcn/ui/sidebar.rb +420 -0
- data/lib/shadcn/ui/skeleton.rb +23 -0
- data/lib/shadcn/ui/slider.rb +72 -0
- data/lib/shadcn/ui/sonner.rb +177 -0
- data/lib/shadcn/ui/spinner.rb +58 -0
- data/lib/shadcn/ui/switch.rb +75 -0
- data/lib/shadcn/ui/table.rb +154 -0
- data/lib/shadcn/ui/tabs.rb +154 -0
- data/lib/shadcn/ui/text_field.rb +146 -0
- data/lib/shadcn/ui/textarea.rb +32 -0
- data/lib/shadcn/ui/theme_toggle.rb +74 -0
- data/lib/shadcn/ui/toggle.rb +66 -0
- data/lib/shadcn/ui/toggle_group.rb +75 -0
- data/lib/shadcn/ui/tooltip.rb +78 -0
- data/lib/shadcn/ui/typography.rb +217 -0
- data/lib/shadcn/version.rb +5 -0
- data/lib/shadcn-phlex.rb +6 -0
- data/lib/shadcn.rb +80 -0
- data/package.json +14 -0
- data/skills/shadcn-phlex/SKILL.md +190 -0
- data/skills/shadcn-phlex/evals/evals.json +90 -0
- data/skills/shadcn-phlex/references/component-catalog.md +355 -0
- data/skills/shadcn-phlex/rules/composition.md +235 -0
- data/skills/shadcn-phlex/rules/forms.md +151 -0
- data/skills/shadcn-phlex/rules/helpers.md +54 -0
- data/skills/shadcn-phlex/rules/stimulus.md +61 -0
- data/skills/shadcn-phlex/rules/styling.md +177 -0
- metadata +209 -0
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module UI
|
|
5
|
+
# Port of shadcn/ui NavigationMenu
|
|
6
|
+
class NavigationMenu < Base
|
|
7
|
+
def initialize(viewport: true, **attrs)
|
|
8
|
+
@viewport = viewport
|
|
9
|
+
@attrs = attrs
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def view_template(&block)
|
|
13
|
+
nav(**build_attrs) do
|
|
14
|
+
yield if block_given?
|
|
15
|
+
render NavigationMenuViewport.new if @viewport
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def build_attrs
|
|
22
|
+
classes = cn(
|
|
23
|
+
"group/navigation-menu relative flex max-w-max flex-1 items-center justify-center",
|
|
24
|
+
@attrs.delete(:class)
|
|
25
|
+
)
|
|
26
|
+
@attrs.merge(
|
|
27
|
+
data_slot: "navigation-menu",
|
|
28
|
+
data_controller: "shadcn--navigation-menu",
|
|
29
|
+
data_viewport: @viewport,
|
|
30
|
+
class: classes
|
|
31
|
+
)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
class NavigationMenuList < Base
|
|
36
|
+
def initialize(**attrs)
|
|
37
|
+
@attrs = attrs
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def view_template(&block)
|
|
41
|
+
ul(**build_attrs, &block)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private
|
|
45
|
+
|
|
46
|
+
def build_attrs
|
|
47
|
+
classes = cn(
|
|
48
|
+
"group flex flex-1 list-none items-center justify-center gap-1",
|
|
49
|
+
@attrs.delete(:class)
|
|
50
|
+
)
|
|
51
|
+
@attrs.merge(data_slot: "navigation-menu-list", class: classes)
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
class NavigationMenuItem < Base
|
|
56
|
+
def initialize(**attrs)
|
|
57
|
+
@attrs = attrs
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def view_template(&block)
|
|
61
|
+
li(**build_attrs, &block)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
private
|
|
65
|
+
|
|
66
|
+
def build_attrs
|
|
67
|
+
classes = cn("relative", @attrs.delete(:class))
|
|
68
|
+
@attrs.merge(data_slot: "navigation-menu-item", class: classes)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
class NavigationMenuTrigger < Base
|
|
73
|
+
def initialize(**attrs)
|
|
74
|
+
@attrs = attrs
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def view_template(&block)
|
|
78
|
+
button(**build_attrs) do
|
|
79
|
+
yield if block_given?
|
|
80
|
+
plain " "
|
|
81
|
+
svg(
|
|
82
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
83
|
+
width: "12", 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: "relative top-[1px] ml-1 size-3 transition duration-300 group-data-[state=open]:rotate-180",
|
|
91
|
+
aria_hidden: "true"
|
|
92
|
+
) do |s|
|
|
93
|
+
s.path(d: "m6 9 6 6 6-6")
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
private
|
|
99
|
+
|
|
100
|
+
def build_attrs
|
|
101
|
+
classes = cn(
|
|
102
|
+
"group inline-flex h-9 w-max items-center justify-center rounded-md bg-background px-4 py-2 text-sm font-medium",
|
|
103
|
+
"transition-[color,box-shadow] outline-none",
|
|
104
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
105
|
+
"focus:bg-accent focus:text-accent-foreground",
|
|
106
|
+
"focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1",
|
|
107
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
108
|
+
"data-[state=open]:bg-accent/50 data-[state=open]:text-accent-foreground",
|
|
109
|
+
@attrs.delete(:class)
|
|
110
|
+
)
|
|
111
|
+
@attrs.merge(
|
|
112
|
+
data_slot: "navigation-menu-trigger",
|
|
113
|
+
data_shadcn__navigation_menu_target: "trigger",
|
|
114
|
+
data_action: "mouseenter->shadcn--navigation-menu#enterTrigger mouseleave->shadcn--navigation-menu#leaveTrigger click->shadcn--navigation-menu#clickTrigger keydown->shadcn--navigation-menu#keydown",
|
|
115
|
+
type: "button",
|
|
116
|
+
class: classes
|
|
117
|
+
)
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
class NavigationMenuContent < Base
|
|
122
|
+
def initialize(**attrs)
|
|
123
|
+
@attrs = attrs
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def view_template(&block)
|
|
127
|
+
div(**build_attrs, &block)
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
private
|
|
131
|
+
|
|
132
|
+
def build_attrs
|
|
133
|
+
classes = cn(
|
|
134
|
+
"top-0 left-0 w-full p-2 pr-2.5",
|
|
135
|
+
"data-[motion=from-end]:slide-in-from-right-52 data-[motion=from-start]:slide-in-from-left-52",
|
|
136
|
+
"data-[motion=to-end]:slide-out-to-right-52 data-[motion=to-start]:slide-out-to-left-52",
|
|
137
|
+
"data-[motion^=from-]:animate-in data-[motion^=from-]:fade-in",
|
|
138
|
+
"data-[motion^=to-]:animate-out data-[motion^=to-]:fade-out",
|
|
139
|
+
"md:absolute md:w-auto",
|
|
140
|
+
@attrs.delete(:class)
|
|
141
|
+
)
|
|
142
|
+
@attrs.merge(
|
|
143
|
+
data_slot: "navigation-menu-content",
|
|
144
|
+
data_shadcn__navigation_menu_target: "content",
|
|
145
|
+
data_action: "mouseenter->shadcn--navigation-menu#enterContent mouseleave->shadcn--navigation-menu#leaveContent keydown->shadcn--navigation-menu#contentKeydown",
|
|
146
|
+
hidden: true,
|
|
147
|
+
class: classes
|
|
148
|
+
)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
class NavigationMenuViewport < Base
|
|
153
|
+
def initialize(**attrs)
|
|
154
|
+
@attrs = attrs
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def view_template
|
|
158
|
+
div(class: "absolute top-full left-0 isolate z-50 flex justify-center") do
|
|
159
|
+
div(**build_attrs)
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
private
|
|
164
|
+
|
|
165
|
+
def build_attrs
|
|
166
|
+
classes = cn(
|
|
167
|
+
"origin-top-center relative mt-1.5 w-full overflow-hidden rounded-md border bg-popover text-popover-foreground shadow",
|
|
168
|
+
"data-[state=closed]:animate-out data-[state=closed]:zoom-out-95",
|
|
169
|
+
"data-[state=open]:animate-in data-[state=open]:zoom-in-90",
|
|
170
|
+
@attrs.delete(:class)
|
|
171
|
+
)
|
|
172
|
+
@attrs.merge(
|
|
173
|
+
data_slot: "navigation-menu-viewport",
|
|
174
|
+
data_shadcn__navigation_menu_target: "viewport",
|
|
175
|
+
hidden: true,
|
|
176
|
+
class: classes
|
|
177
|
+
)
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
class NavigationMenuLink < Base
|
|
182
|
+
def initialize(href: "#", active: false, **attrs)
|
|
183
|
+
@href = href
|
|
184
|
+
@active = active
|
|
185
|
+
@attrs = attrs
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def view_template(&block)
|
|
189
|
+
a(**build_attrs, &block)
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
private
|
|
193
|
+
|
|
194
|
+
def build_attrs
|
|
195
|
+
classes = cn(
|
|
196
|
+
"flex flex-col gap-1 rounded-sm p-2 text-sm transition-all outline-none",
|
|
197
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
198
|
+
"focus:bg-accent focus:text-accent-foreground",
|
|
199
|
+
"focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1",
|
|
200
|
+
"data-[active=true]:bg-accent/50 data-[active=true]:text-accent-foreground",
|
|
201
|
+
"[&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
|
|
202
|
+
@attrs.delete(:class)
|
|
203
|
+
)
|
|
204
|
+
@attrs.merge(
|
|
205
|
+
data_slot: "navigation-menu-link",
|
|
206
|
+
data_shadcn__navigation_menu_target: "link",
|
|
207
|
+
data_active: @active,
|
|
208
|
+
href: @href,
|
|
209
|
+
class: classes
|
|
210
|
+
)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
class NavigationMenuIndicator < Base
|
|
215
|
+
def initialize(**attrs)
|
|
216
|
+
@attrs = attrs
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
def view_template
|
|
220
|
+
div(**build_attrs) do
|
|
221
|
+
div(class: "relative top-[60%] h-2 w-2 rotate-45 rounded-tl-sm bg-border shadow-md")
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
private
|
|
226
|
+
|
|
227
|
+
def build_attrs
|
|
228
|
+
classes = cn(
|
|
229
|
+
"top-full z-[1] flex h-1.5 items-end justify-center overflow-hidden",
|
|
230
|
+
"data-[state=hidden]:animate-out data-[state=hidden]:fade-out",
|
|
231
|
+
"data-[state=visible]:animate-in data-[state=visible]:fade-in",
|
|
232
|
+
@attrs.delete(:class)
|
|
233
|
+
)
|
|
234
|
+
@attrs.merge(data_slot: "navigation-menu-indicator", class: classes)
|
|
235
|
+
end
|
|
236
|
+
end
|
|
237
|
+
end
|
|
238
|
+
end
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module UI
|
|
5
|
+
# Port of shadcn/ui Pagination
|
|
6
|
+
class Pagination < Base
|
|
7
|
+
def initialize(**attrs)
|
|
8
|
+
@attrs = attrs
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def view_template(&block)
|
|
12
|
+
nav(**build_attrs, &block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def build_attrs
|
|
18
|
+
classes = cn("mx-auto flex w-full justify-center", @attrs.delete(:class))
|
|
19
|
+
@attrs.merge(
|
|
20
|
+
data_slot: "pagination",
|
|
21
|
+
role: "navigation",
|
|
22
|
+
aria_label: "pagination",
|
|
23
|
+
class: classes
|
|
24
|
+
)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class PaginationContent < Base
|
|
29
|
+
def initialize(**attrs)
|
|
30
|
+
@attrs = attrs
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def view_template(&block)
|
|
34
|
+
ul(**build_attrs, &block)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def build_attrs
|
|
40
|
+
classes = cn("flex flex-row items-center gap-1", @attrs.delete(:class))
|
|
41
|
+
@attrs.merge(data_slot: "pagination-content", class: classes)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
class PaginationItem < Base
|
|
46
|
+
def initialize(**attrs)
|
|
47
|
+
@attrs = attrs
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def view_template(&block)
|
|
51
|
+
li(**build_attrs, &block)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def build_attrs
|
|
57
|
+
@attrs.merge(data_slot: "pagination-item")
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class PaginationLink < Base
|
|
62
|
+
def initialize(href: "#", active: false, size: :icon, **attrs)
|
|
63
|
+
@href = href
|
|
64
|
+
@active = active
|
|
65
|
+
@size = size
|
|
66
|
+
@attrs = attrs
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def view_template(&block)
|
|
70
|
+
a(**build_attrs, &block)
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
private
|
|
74
|
+
|
|
75
|
+
def build_attrs
|
|
76
|
+
size_class = case @size
|
|
77
|
+
when :icon then "size-9"
|
|
78
|
+
when :default then "h-9 px-4 py-2"
|
|
79
|
+
else "h-9 px-4 py-2"
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
classes = cn(
|
|
83
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium",
|
|
84
|
+
"transition-all cursor-pointer border border-input bg-background shadow-xs",
|
|
85
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
86
|
+
size_class,
|
|
87
|
+
@active ? "border-primary bg-primary text-primary-foreground" : "",
|
|
88
|
+
@attrs.delete(:class)
|
|
89
|
+
)
|
|
90
|
+
result = @attrs.merge(
|
|
91
|
+
data_slot: "pagination-link",
|
|
92
|
+
href: @href,
|
|
93
|
+
class: classes
|
|
94
|
+
)
|
|
95
|
+
result[:aria_current] = "page" if @active
|
|
96
|
+
result
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
class PaginationPrevious < Base
|
|
101
|
+
def initialize(href: "#", **attrs)
|
|
102
|
+
@href = href
|
|
103
|
+
@attrs = attrs
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def view_template(&block)
|
|
107
|
+
a(**build_attrs) do
|
|
108
|
+
svg(
|
|
109
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
110
|
+
width: "16", height: "16",
|
|
111
|
+
viewbox: "0 0 24 24",
|
|
112
|
+
fill: "none",
|
|
113
|
+
stroke: "currentColor",
|
|
114
|
+
stroke_width: "2",
|
|
115
|
+
stroke_linecap: "round",
|
|
116
|
+
stroke_linejoin: "round",
|
|
117
|
+
class: "size-4"
|
|
118
|
+
) do |s|
|
|
119
|
+
s.path(d: "m15 18-6-6 6-6")
|
|
120
|
+
end
|
|
121
|
+
span { "Previous" }
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
|
|
127
|
+
def build_attrs
|
|
128
|
+
classes = cn(
|
|
129
|
+
"inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium",
|
|
130
|
+
"h-9 px-4 py-2 cursor-pointer border border-input bg-background shadow-xs",
|
|
131
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
132
|
+
@attrs.delete(:class)
|
|
133
|
+
)
|
|
134
|
+
@attrs.merge(
|
|
135
|
+
data_slot: "pagination-previous",
|
|
136
|
+
href: @href,
|
|
137
|
+
aria_label: "Go to previous page",
|
|
138
|
+
class: classes
|
|
139
|
+
)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
class PaginationNext < Base
|
|
144
|
+
def initialize(href: "#", **attrs)
|
|
145
|
+
@href = href
|
|
146
|
+
@attrs = attrs
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def view_template(&block)
|
|
150
|
+
a(**build_attrs) do
|
|
151
|
+
span { "Next" }
|
|
152
|
+
svg(
|
|
153
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
154
|
+
width: "16", height: "16",
|
|
155
|
+
viewbox: "0 0 24 24",
|
|
156
|
+
fill: "none",
|
|
157
|
+
stroke: "currentColor",
|
|
158
|
+
stroke_width: "2",
|
|
159
|
+
stroke_linecap: "round",
|
|
160
|
+
stroke_linejoin: "round",
|
|
161
|
+
class: "size-4"
|
|
162
|
+
) do |s|
|
|
163
|
+
s.path(d: "m9 18 6-6-6-6")
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
private
|
|
169
|
+
|
|
170
|
+
def build_attrs
|
|
171
|
+
classes = cn(
|
|
172
|
+
"inline-flex items-center justify-center gap-1 whitespace-nowrap rounded-md text-sm font-medium",
|
|
173
|
+
"h-9 px-4 py-2 cursor-pointer border border-input bg-background shadow-xs",
|
|
174
|
+
"hover:bg-accent hover:text-accent-foreground",
|
|
175
|
+
@attrs.delete(:class)
|
|
176
|
+
)
|
|
177
|
+
@attrs.merge(
|
|
178
|
+
data_slot: "pagination-next",
|
|
179
|
+
href: @href,
|
|
180
|
+
aria_label: "Go to next page",
|
|
181
|
+
class: classes
|
|
182
|
+
)
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
class PaginationEllipsis < Base
|
|
187
|
+
def initialize(**attrs)
|
|
188
|
+
@attrs = attrs
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
def view_template
|
|
192
|
+
span(**build_attrs) do
|
|
193
|
+
svg(
|
|
194
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
195
|
+
width: "16", height: "16",
|
|
196
|
+
viewbox: "0 0 24 24",
|
|
197
|
+
fill: "none",
|
|
198
|
+
stroke: "currentColor",
|
|
199
|
+
stroke_width: "2",
|
|
200
|
+
stroke_linecap: "round",
|
|
201
|
+
stroke_linejoin: "round",
|
|
202
|
+
class: "size-4"
|
|
203
|
+
) do |s|
|
|
204
|
+
s.circle(cx: "12", cy: "12", r: "1")
|
|
205
|
+
s.circle(cx: "19", cy: "12", r: "1")
|
|
206
|
+
s.circle(cx: "5", cy: "12", r: "1")
|
|
207
|
+
end
|
|
208
|
+
span(class: "sr-only") { "More pages" }
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
private
|
|
213
|
+
|
|
214
|
+
def build_attrs
|
|
215
|
+
classes = cn("flex size-9 items-center justify-center", @attrs.delete(:class))
|
|
216
|
+
@attrs.merge(
|
|
217
|
+
data_slot: "pagination-ellipsis",
|
|
218
|
+
aria_hidden: "true",
|
|
219
|
+
class: classes
|
|
220
|
+
)
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
end
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module UI
|
|
5
|
+
# Port of shadcn/ui Popover
|
|
6
|
+
class Popover < Base
|
|
7
|
+
def initialize(**attrs)
|
|
8
|
+
@attrs = attrs
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def view_template(&block)
|
|
12
|
+
div(**build_attrs, &block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def build_attrs
|
|
18
|
+
@attrs.merge(
|
|
19
|
+
data_slot: "popover",
|
|
20
|
+
data_controller: "shadcn--popover",
|
|
21
|
+
data_action: "click@window->shadcn--popover#hide keydown.esc@window->shadcn--popover#hideOnEscape"
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class PopoverTrigger < Base
|
|
27
|
+
def initialize(**attrs)
|
|
28
|
+
@attrs = attrs
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def view_template(&block)
|
|
32
|
+
div(**build_attrs, &block)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def build_attrs
|
|
38
|
+
@attrs.merge(
|
|
39
|
+
data_slot: "popover-trigger",
|
|
40
|
+
data_shadcn__popover_target: "trigger",
|
|
41
|
+
data_action: "click->shadcn--popover#toggle",
|
|
42
|
+
role: "button",
|
|
43
|
+
style: "display: inline-block"
|
|
44
|
+
)
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
class PopoverAnchor < Base
|
|
49
|
+
def initialize(**attrs)
|
|
50
|
+
@attrs = attrs
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def view_template(&block)
|
|
54
|
+
div(**build_attrs, &block)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def build_attrs
|
|
60
|
+
@attrs.merge(
|
|
61
|
+
data_slot: "popover-anchor",
|
|
62
|
+
data_shadcn__popover_target: "anchor"
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
class PopoverContent < Base
|
|
68
|
+
def initialize(**attrs)
|
|
69
|
+
@attrs = attrs
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def view_template(&block)
|
|
73
|
+
div(**build_attrs, &block)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
|
|
78
|
+
def build_attrs
|
|
79
|
+
classes = cn(
|
|
80
|
+
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-hidden",
|
|
81
|
+
"data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2",
|
|
82
|
+
"data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
83
|
+
"data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95",
|
|
84
|
+
"data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95",
|
|
85
|
+
@attrs.delete(:class)
|
|
86
|
+
)
|
|
87
|
+
@attrs.merge(
|
|
88
|
+
data_slot: "popover-content",
|
|
89
|
+
data_shadcn__popover_target: "content",
|
|
90
|
+
hidden: true,
|
|
91
|
+
class: classes
|
|
92
|
+
)
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
class PopoverHeader < Base
|
|
97
|
+
def initialize(**attrs)
|
|
98
|
+
@attrs = attrs
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def view_template(&block)
|
|
102
|
+
div(**build_attrs, &block)
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
def build_attrs
|
|
108
|
+
classes = cn("flex flex-col gap-1", @attrs.delete(:class))
|
|
109
|
+
@attrs.merge(data_slot: "popover-header", class: classes)
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
class PopoverTitle < Base
|
|
114
|
+
def initialize(**attrs)
|
|
115
|
+
@attrs = attrs
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def view_template(&block)
|
|
119
|
+
h4(**build_attrs, &block)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
private
|
|
123
|
+
|
|
124
|
+
def build_attrs
|
|
125
|
+
classes = cn("text-sm font-medium leading-none", @attrs.delete(:class))
|
|
126
|
+
@attrs.merge(data_slot: "popover-title", class: classes)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
class PopoverDescription < Base
|
|
131
|
+
def initialize(**attrs)
|
|
132
|
+
@attrs = attrs
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def view_template(&block)
|
|
136
|
+
p(**build_attrs, &block)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
private
|
|
140
|
+
|
|
141
|
+
def build_attrs
|
|
142
|
+
classes = cn("text-sm text-muted-foreground", @attrs.delete(:class))
|
|
143
|
+
@attrs.merge(data_slot: "popover-description", class: classes)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Shadcn
|
|
4
|
+
module UI
|
|
5
|
+
# Port of shadcn/ui Progress
|
|
6
|
+
class Progress < Base
|
|
7
|
+
def initialize(value: 0, **attrs)
|
|
8
|
+
@value = value.to_i.clamp(0, 100)
|
|
9
|
+
@attrs = attrs
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def view_template
|
|
13
|
+
div(**build_attrs) do
|
|
14
|
+
div(
|
|
15
|
+
data_slot: "progress-indicator",
|
|
16
|
+
class: "h-full w-full flex-1 bg-primary transition-all",
|
|
17
|
+
style: "transform: translateX(-#{100 - @value}%)"
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def build_attrs
|
|
25
|
+
classes = cn(
|
|
26
|
+
"relative h-2 w-full overflow-hidden rounded-full bg-primary/20",
|
|
27
|
+
@attrs.delete(:class)
|
|
28
|
+
)
|
|
29
|
+
@attrs.merge(
|
|
30
|
+
data_slot: "progress",
|
|
31
|
+
role: "progressbar",
|
|
32
|
+
aria_valuemin: 0,
|
|
33
|
+
aria_valuemax: 100,
|
|
34
|
+
aria_valuenow: @value,
|
|
35
|
+
class: classes
|
|
36
|
+
)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|