phlex_ui 0.0.3 → 0.0.5
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/lib/phlex_ui/accordion/content.rb +21 -0
- data/lib/phlex_ui/accordion/default_content.rb +17 -0
- data/lib/phlex_ui/accordion/default_trigger.rb +19 -0
- data/lib/phlex_ui/accordion/icon.rb +38 -0
- data/lib/phlex_ui/accordion/item.rb +28 -0
- data/lib/phlex_ui/accordion/trigger.rb +16 -0
- data/lib/phlex_ui/accordion.rb +28 -0
- data/lib/phlex_ui/alert/description.rb +17 -0
- data/lib/phlex_ui/alert/title.rb +17 -0
- data/lib/phlex_ui/alert.rb +36 -0
- data/lib/phlex_ui/alert_dialog/action.rb +17 -0
- data/lib/phlex_ui/alert_dialog/cancel.rb +21 -0
- data/lib/phlex_ui/alert_dialog/content.rb +45 -0
- data/lib/phlex_ui/alert_dialog/description.rb +17 -0
- data/lib/phlex_ui/alert_dialog/footer.rb +17 -0
- data/lib/phlex_ui/alert_dialog/header.rb +17 -0
- data/lib/phlex_ui/alert_dialog/title.rb +17 -0
- data/lib/phlex_ui/alert_dialog/trigger.rb +18 -0
- data/lib/phlex_ui/alert_dialog.rb +26 -0
- data/lib/phlex_ui/aspect_ratio.rb +33 -0
- data/lib/phlex_ui/attribute_merger.rb +75 -0
- data/lib/phlex_ui/avatar/fallback.rb +17 -0
- data/lib/phlex_ui/avatar/image.rb +26 -0
- data/lib/phlex_ui/avatar.rb +49 -0
- data/lib/phlex_ui/badge.rb +60 -0
- data/lib/phlex_ui/base.rb +24 -0
- data/lib/phlex_ui/button.rb +85 -16
- data/lib/phlex_ui/card/content.rb +17 -0
- data/lib/phlex_ui/card/description.rb +17 -0
- data/lib/phlex_ui/card/footer.rb +17 -0
- data/lib/phlex_ui/card/header.rb +17 -0
- data/lib/phlex_ui/card/title.rb +17 -0
- data/lib/phlex_ui/card.rb +17 -0
- data/lib/phlex_ui/checkbox.rb +18 -0
- data/lib/phlex_ui/clipboard/popover.rb +36 -0
- data/lib/phlex_ui/clipboard/source.rb +19 -0
- data/lib/phlex_ui/clipboard/trigger.rb +20 -0
- data/lib/phlex_ui/clipboard.rb +39 -0
- data/lib/phlex_ui/codeblock.rb +105 -0
- data/lib/phlex_ui/collapsible/content.rb +18 -0
- data/lib/phlex_ui/collapsible/trigger.rb +19 -0
- data/lib/phlex_ui/collapsible.rb +25 -0
- data/lib/phlex_ui/context_menu/content.rb +25 -0
- data/lib/phlex_ui/context_menu/item.rb +66 -0
- data/lib/phlex_ui/context_menu/label.rb +24 -0
- data/lib/phlex_ui/context_menu/separator.rb +19 -0
- data/lib/phlex_ui/context_menu/trigger.rb +20 -0
- data/lib/phlex_ui/context_menu.rb +26 -0
- data/lib/phlex_ui/dialog/content.rb +78 -0
- data/lib/phlex_ui/dialog/description.rb +17 -0
- data/lib/phlex_ui/dialog/footer.rb +17 -0
- data/lib/phlex_ui/dialog/header.rb +17 -0
- data/lib/phlex_ui/dialog/middle.rb +17 -0
- data/lib/phlex_ui/dialog/title.rb +17 -0
- data/lib/phlex_ui/dialog/trigger.rb +19 -0
- data/lib/phlex_ui/dialog.rb +25 -0
- data/lib/phlex_ui/dropdown_menu/content.rb +22 -0
- data/lib/phlex_ui/dropdown_menu/item.rb +28 -0
- data/lib/phlex_ui/dropdown_menu/label.rb +17 -0
- data/lib/phlex_ui/dropdown_menu/separator.rb +19 -0
- data/lib/phlex_ui/dropdown_menu/trigger.rb +17 -0
- data/lib/phlex_ui/dropdown_menu.rb +26 -0
- data/lib/phlex_ui/form/item.rb +17 -0
- data/lib/phlex_ui/form/spacer.rb +17 -0
- data/lib/phlex_ui/form.rb +34 -0
- data/lib/phlex_ui/hint.rb +17 -0
- data/lib/phlex_ui/hover_card/content.rb +22 -0
- data/lib/phlex_ui/hover_card/trigger.rb +19 -0
- data/lib/phlex_ui/hover_card.rb +27 -0
- data/lib/phlex_ui/input.rb +29 -0
- data/lib/phlex_ui/input_error.rb +17 -0
- data/lib/phlex_ui/label.rb +17 -0
- data/lib/phlex_ui/link.rb +97 -0
- data/lib/phlex_ui/popover/content.rb +22 -0
- data/lib/phlex_ui/popover/trigger.rb +19 -0
- data/lib/phlex_ui/popover.rb +25 -0
- data/lib/phlex_ui/shortcut_key.rb +17 -0
- data/lib/phlex_ui/table/body.rb +17 -0
- data/lib/phlex_ui/table/builder.rb +77 -0
- data/lib/phlex_ui/table/caption.rb +17 -0
- data/lib/phlex_ui/table/cell.rb +17 -0
- data/lib/phlex_ui/table/footer.rb +17 -0
- data/lib/phlex_ui/table/head.rb +17 -0
- data/lib/phlex_ui/table/header.rb +17 -0
- data/lib/phlex_ui/table/row.rb +17 -0
- data/lib/phlex_ui/table.rb +19 -0
- data/lib/phlex_ui/tabs/content.rb +26 -0
- data/lib/phlex_ui/tabs/list.rb +17 -0
- data/lib/phlex_ui/tabs/trigger.rb +28 -0
- data/lib/phlex_ui/tabs.rb +25 -0
- data/lib/phlex_ui/theme_toggle.rb +41 -0
- data/lib/phlex_ui/tooltip/content.rb +22 -0
- data/lib/phlex_ui/tooltip/trigger.rb +17 -0
- data/lib/phlex_ui/tooltip.rb +25 -0
- data/lib/phlex_ui/typography/blockquote.rb +17 -0
- data/lib/phlex_ui/typography/h1.rb +17 -0
- data/lib/phlex_ui/typography/h2.rb +17 -0
- data/lib/phlex_ui/typography/h3.rb +17 -0
- data/lib/phlex_ui/typography/h4.rb +17 -0
- data/lib/phlex_ui/typography/inline_code.rb +17 -0
- data/lib/phlex_ui/typography/large.rb +17 -0
- data/lib/phlex_ui/typography/lead.rb +17 -0
- data/lib/phlex_ui/typography/list.rb +47 -0
- data/lib/phlex_ui/typography/list_item.rb +17 -0
- data/lib/phlex_ui/typography/muted.rb +17 -0
- data/lib/phlex_ui/typography/p.rb +17 -0
- data/lib/phlex_ui/typography/small.rb +17 -0
- data/lib/phlex_ui.rb +0 -8
- metadata +113 -28
- data/tasks/install.rake +0 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 997466eeaf90ee785e93f2bbb17ddf3014db28e538cfd2b5bb1177800b7eff41
|
|
4
|
+
data.tar.gz: a876736cf42046f4eda6e974ca8d48a2ffceb29dc49679bf2a857815a2d14c4e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ca6af73e57c9c22983f4eab367a894bbcdba53e8b16b707ec14accf80f1faa81994f45f2ea34ffb1867cc800875bce96c7d716043f418b1aa88aa1adfcc3049d
|
|
7
|
+
data.tar.gz: 6fb432282362714d0a1b048e476dc15d7ad38f60ef26c311eaeefe35fcca31b9b34b72224f61147b991fd832c148f1380fa556eb878abe5ecf27dd3a50c8ea46
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class Accordion::Content < Base
|
|
5
|
+
def template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
data: {
|
|
14
|
+
accordion_target: "content"
|
|
15
|
+
},
|
|
16
|
+
class: 'overflow-y-hidden',
|
|
17
|
+
style: 'height: 0px;'
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class Accordion::DefaultTrigger < Base
|
|
5
|
+
def template(&)
|
|
6
|
+
div(class: "flex items-center justify-between w-full") do
|
|
7
|
+
p(&)
|
|
8
|
+
render ::PhlexUI::Accordion::Icon.new
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def default_attrs
|
|
13
|
+
{
|
|
14
|
+
data: { action: "click->accordion#toggle" },
|
|
15
|
+
class: 'w-full flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline'
|
|
16
|
+
}
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class Accordion::Icon < Base
|
|
5
|
+
def template(&block)
|
|
6
|
+
span(**attrs) do
|
|
7
|
+
if block
|
|
8
|
+
block.call
|
|
9
|
+
else
|
|
10
|
+
icon
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def icon
|
|
16
|
+
svg(
|
|
17
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
18
|
+
viewbox: "0 0 20 20",
|
|
19
|
+
fill: "currentColor",
|
|
20
|
+
class: "w-4 h-4"
|
|
21
|
+
) do |s|
|
|
22
|
+
s.path(
|
|
23
|
+
fill_rule: "evenodd",
|
|
24
|
+
d:
|
|
25
|
+
"M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z",
|
|
26
|
+
clip_rule: "evenodd"
|
|
27
|
+
)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def default_attrs
|
|
32
|
+
{
|
|
33
|
+
class: 'opacity-50',
|
|
34
|
+
data: { accordion_target: "icon" },
|
|
35
|
+
}
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class Accordion::Item < Base
|
|
5
|
+
def initialize(open: false, rotate_icon: 180, **attrs)
|
|
6
|
+
@open = open
|
|
7
|
+
@rotate_icon = rotate_icon
|
|
8
|
+
super(**attrs)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def template(&)
|
|
12
|
+
div(**attrs, &)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def default_attrs
|
|
18
|
+
{
|
|
19
|
+
data: {
|
|
20
|
+
controller: "accordion",
|
|
21
|
+
accordion_open_value: @open,
|
|
22
|
+
accordion_rotate_icon_value: @rotate_icon
|
|
23
|
+
},
|
|
24
|
+
class: 'border-b'
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class Accordion::Trigger < Base
|
|
5
|
+
def template(&)
|
|
6
|
+
button(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def default_attrs
|
|
10
|
+
{
|
|
11
|
+
data: { action: "click->accordion#toggle" },
|
|
12
|
+
class: 'w-full flex flex-1 items-center justify-between py-4 text-sm font-medium transition-all hover:underline'
|
|
13
|
+
}
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class Accordion < Base
|
|
5
|
+
def template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def add_item(title, content, open: false)
|
|
10
|
+
render Accordion::Item.new(open: open) do
|
|
11
|
+
render PhlexUI::Accordion::Trigger.new do
|
|
12
|
+
render PhlexUI::Accordion::DefaultTrigger.new { title }
|
|
13
|
+
end
|
|
14
|
+
render PhlexUI::Accordion::Content.new do
|
|
15
|
+
render PhlexUI::Accordion::DefaultContent.new { content }
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
private
|
|
21
|
+
|
|
22
|
+
def default_attrs
|
|
23
|
+
{
|
|
24
|
+
class: 'w-full'
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class Alert < Base
|
|
5
|
+
def initialize(variant: nil, **attrs)
|
|
6
|
+
@variant = variant
|
|
7
|
+
super(**attrs) # must be called after variant is set
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def template(&)
|
|
11
|
+
div(**attrs, &)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def colors
|
|
17
|
+
case @variant
|
|
18
|
+
when nil
|
|
19
|
+
'ring-border bg-muted-background text-text [&>svg]:opacity-80'
|
|
20
|
+
when :warning
|
|
21
|
+
'ring-warning/20 bg-warning/10 text-warning [&>svg]:text-warning/80'
|
|
22
|
+
when :success
|
|
23
|
+
'ring-success/20 bg-success/10 text-success [&>svg]:text-success/80'
|
|
24
|
+
when :destructive
|
|
25
|
+
'ring-destructive/10 dark:ring-destructive/20 text-destructive bg-destructive/10 [&>svg]:text-destructive/80'
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def default_attrs
|
|
30
|
+
base_classes = 'relative w-full ring-1 ring-inset rounded-lg px-4 py-4 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg~*]:pl-8'
|
|
31
|
+
{
|
|
32
|
+
class: tokens(base_classes, colors),
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class AlertDialog::Cancel < Base
|
|
5
|
+
def template(&)
|
|
6
|
+
render PhlexUI::Button.new(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
variant: :outline,
|
|
14
|
+
data: {
|
|
15
|
+
action: 'click->dismissable#dismiss'
|
|
16
|
+
},
|
|
17
|
+
class: 'mt-2 sm:mt-0'
|
|
18
|
+
}
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class AlertDialog::Content < Base
|
|
5
|
+
def template(&)
|
|
6
|
+
template_tag(**attrs) do
|
|
7
|
+
div(data: { controller: 'dismissable' }) do
|
|
8
|
+
background
|
|
9
|
+
container(&)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def background
|
|
15
|
+
div(
|
|
16
|
+
data_state: "open",
|
|
17
|
+
class:
|
|
18
|
+
"fixed inset-0 z-50 bg-background/80 backdrop-blur-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
19
|
+
style: "pointer-events:auto",
|
|
20
|
+
data_aria_hidden: "true",
|
|
21
|
+
aria_hidden: "true"
|
|
22
|
+
)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def container(&)
|
|
26
|
+
div(
|
|
27
|
+
role: "alertdialog",
|
|
28
|
+
data_state: "open",
|
|
29
|
+
class: "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg md:w-full",
|
|
30
|
+
style: "pointer-events:auto",
|
|
31
|
+
&
|
|
32
|
+
)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def default_attrs
|
|
38
|
+
{
|
|
39
|
+
data: {
|
|
40
|
+
alert_dialog_target: "content"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class AlertDialog::Footer < Base
|
|
5
|
+
def template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2"
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class AlertDialog::Header < Base
|
|
5
|
+
def template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: "flex flex-col space-y-2 text-center sm:text-left"
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class AlertDialog::Trigger < Base
|
|
5
|
+
def template(&)
|
|
6
|
+
div(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
data: { action: "click->alert-dialog#open" },
|
|
14
|
+
class: 'inline-block'
|
|
15
|
+
}
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class AlertDialog < Base
|
|
5
|
+
def initialize(open: false, **attrs)
|
|
6
|
+
@open = open
|
|
7
|
+
super(**attrs)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def template(&)
|
|
11
|
+
div(**attrs, &)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
private
|
|
15
|
+
|
|
16
|
+
def default_attrs
|
|
17
|
+
{
|
|
18
|
+
data: {
|
|
19
|
+
controller: 'alert-dialog',
|
|
20
|
+
alert_dialog_open_value: @open
|
|
21
|
+
},
|
|
22
|
+
class: 'inline-block'
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class AspectRatio < Base
|
|
5
|
+
def initialize(aspect_ratio: "16/9", **attrs)
|
|
6
|
+
raise "aspect_ratio must be in the format of a string with a slash in the middle (eg. '16/9', '1/1')" unless aspect_ratio.is_a?(String) && aspect_ratio.include?("/")
|
|
7
|
+
|
|
8
|
+
@aspect_ratio = aspect_ratio
|
|
9
|
+
super(**attrs)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def template(&)
|
|
13
|
+
div(
|
|
14
|
+
class: "relative w-full",
|
|
15
|
+
style: "padding-bottom: #{padding_bottom}%;",
|
|
16
|
+
) do
|
|
17
|
+
div(**attrs, &)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def padding_bottom
|
|
24
|
+
@aspect_ratio.split("/").map(&:to_i).reverse.reduce(&:fdiv) * 100
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def default_attrs
|
|
28
|
+
{
|
|
29
|
+
class: "bg-muted-background absolute inset-0 [&>img]:object-cover [&>img]:absolute [&>img]:h-full [&>img]:w-full [&>img]:inset-0 [&>img]:text-transparent"
|
|
30
|
+
}
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
module PhlexUI
|
|
2
|
+
class AttributeMerger
|
|
3
|
+
attr_reader :default_attrs, :user_attrs
|
|
4
|
+
OVERRIDE_KEY = '!'.freeze
|
|
5
|
+
|
|
6
|
+
def initialize(default_attrs, user_attrs)
|
|
7
|
+
@default_attrs = flatten_hash(default_attrs)
|
|
8
|
+
@user_attrs = flatten_hash(user_attrs)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def call
|
|
12
|
+
merged_attrs = merge_hashes(default_attrs, non_override_attrs)
|
|
13
|
+
mix(merged_attrs, override_attrs)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
# @return [Hash]
|
|
19
|
+
def mix(*args)
|
|
20
|
+
args.each_with_object({}) do |object, result|
|
|
21
|
+
result.merge!(object) do |_key, old, new|
|
|
22
|
+
case new
|
|
23
|
+
when Hash
|
|
24
|
+
old.is_a?(Hash) ? mix(old, new) : new
|
|
25
|
+
when Array
|
|
26
|
+
old.is_a?(Array) ? (old + new) : new
|
|
27
|
+
when String
|
|
28
|
+
old.is_a?(String) ? "#{old} #{new}" : new
|
|
29
|
+
else
|
|
30
|
+
new
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
result.transform_keys! do |key|
|
|
35
|
+
key.end_with?("!") ? key.name.chop.to_sym : key
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def override_attrs
|
|
41
|
+
user_attrs.select do |key, value|
|
|
42
|
+
key.to_s.include?(OVERRIDE_KEY)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def non_override_attrs
|
|
47
|
+
user_attrs.reject do |key, value|
|
|
48
|
+
key.to_s.include?(OVERRIDE_KEY)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def flatten_hash(hash, parent_key = '', result_hash = {})
|
|
53
|
+
hash.each do |key, value|
|
|
54
|
+
new_key = parent_key.empty? ? key : "#{parent_key}_#{key}".to_sym
|
|
55
|
+
if value.is_a? Hash
|
|
56
|
+
flatten_hash(value, new_key, result_hash)
|
|
57
|
+
else
|
|
58
|
+
result_hash[new_key] = value
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
result_hash
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def merge_hashes(hash1, hash2)
|
|
65
|
+
flat_hash1 = flatten_hash(hash1)
|
|
66
|
+
flat_hash2 = flatten_hash(hash2)
|
|
67
|
+
|
|
68
|
+
merged = flat_hash1.merge(flat_hash2) do |key, oldval, newval|
|
|
69
|
+
"#{oldval} #{newval}"
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
merged
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class Avatar::Fallback < Base
|
|
5
|
+
def template(&)
|
|
6
|
+
span(**attrs, &)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
private
|
|
10
|
+
|
|
11
|
+
def default_attrs
|
|
12
|
+
{
|
|
13
|
+
class: "flex h-full w-full items-center justify-center rounded-full bg-muted-background"
|
|
14
|
+
}
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class Avatar::Image < Base
|
|
5
|
+
def initialize(src:, alt: '', **attrs)
|
|
6
|
+
@src = src
|
|
7
|
+
@alt = alt
|
|
8
|
+
super(**attrs)
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def template
|
|
12
|
+
img(**attrs)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
|
|
17
|
+
def default_attrs
|
|
18
|
+
{
|
|
19
|
+
loading: "lazy",
|
|
20
|
+
class: "aspect-square h-full w-full",
|
|
21
|
+
alt: @alt,
|
|
22
|
+
src: @src
|
|
23
|
+
}
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module PhlexUI
|
|
4
|
+
class Avatar < Base
|
|
5
|
+
SIZES = {
|
|
6
|
+
xs: "h-4 w-4 text-[0.5rem]",
|
|
7
|
+
sm: "h-6 w-6 text-xs",
|
|
8
|
+
md: "h-10 w-10 text-base",
|
|
9
|
+
lg: "h-14 w-14 text-xl",
|
|
10
|
+
xl: "h-20 w-20 text-3xl"
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
def initialize(size: :md, src: nil, alt: nil, initials: nil, **attrs)
|
|
14
|
+
@size = size
|
|
15
|
+
@src = src
|
|
16
|
+
@alt = alt
|
|
17
|
+
@initials = initials
|
|
18
|
+
@size_classes = SIZES[@size]
|
|
19
|
+
super(**attrs)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def template(&block)
|
|
23
|
+
if block_given?
|
|
24
|
+
span(**attrs, &block)
|
|
25
|
+
else
|
|
26
|
+
span(**attrs) do
|
|
27
|
+
render_image if @src
|
|
28
|
+
render_initials
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
private
|
|
34
|
+
|
|
35
|
+
def render_image
|
|
36
|
+
render ::PhlexUI::Avatar::Image.new(src: @src, alt: @alt)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def render_initials
|
|
40
|
+
render ::PhlexUI::Avatar::Fallback.new { @initials }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def default_attrs
|
|
44
|
+
{
|
|
45
|
+
class: tokens("relative flex shrink-0 overflow-hidden rounded-full", @size_classes)
|
|
46
|
+
}
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|