protos 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +12 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +150 -0
- data/Rakefile +12 -0
- data/examples/navbar.rb +43 -0
- data/lib/protos/accordion/item.rb +33 -0
- data/lib/protos/accordion.rb +34 -0
- data/lib/protos/alert/actions.rb +19 -0
- data/lib/protos/alert/icon.rb +19 -0
- data/lib/protos/alert.rb +46 -0
- data/lib/protos/attributes.rb +42 -0
- data/lib/protos/avatar.rb +71 -0
- data/lib/protos/card/actions.rb +19 -0
- data/lib/protos/card/body.rb +19 -0
- data/lib/protos/card/image.rb +11 -0
- data/lib/protos/card/title.rb +19 -0
- data/lib/protos/card.rb +55 -0
- data/lib/protos/collapse/content.rb +19 -0
- data/lib/protos/collapse/title.rb +19 -0
- data/lib/protos/collapse.rb +31 -0
- data/lib/protos/combobox.rb +53 -0
- data/lib/protos/command/dialog.rb +32 -0
- data/lib/protos/command/empty.rb +25 -0
- data/lib/protos/command/group.rb +13 -0
- data/lib/protos/command/input.rb +44 -0
- data/lib/protos/command/item.rb +19 -0
- data/lib/protos/command/list.rb +19 -0
- data/lib/protos/command/title.rb +19 -0
- data/lib/protos/command/trigger.rb +19 -0
- data/lib/protos/command.rb +49 -0
- data/lib/protos/component.rb +79 -0
- data/lib/protos/drawer/content.rb +19 -0
- data/lib/protos/drawer/side.rb +25 -0
- data/lib/protos/drawer/trigger.rb +21 -0
- data/lib/protos/drawer.rb +35 -0
- data/lib/protos/dropdown/item.rb +11 -0
- data/lib/protos/dropdown/menu.rb +25 -0
- data/lib/protos/dropdown/trigger.rb +11 -0
- data/lib/protos/dropdown.rb +59 -0
- data/lib/protos/engine.rb +7 -0
- data/lib/protos/list/item.rb +22 -0
- data/lib/protos/list.rb +30 -0
- data/lib/protos/modal/close_button.rb +16 -0
- data/lib/protos/modal/dialog.rb +30 -0
- data/lib/protos/modal/trigger.rb +19 -0
- data/lib/protos/modal.rb +31 -0
- data/lib/protos/popover/content.rb +19 -0
- data/lib/protos/popover/trigger.rb +11 -0
- data/lib/protos/popover.rb +54 -0
- data/lib/protos/table/body.rb +11 -0
- data/lib/protos/table/caption.rb +19 -0
- data/lib/protos/table/cell.rb +11 -0
- data/lib/protos/table/footer.rb +11 -0
- data/lib/protos/table/head.rb +11 -0
- data/lib/protos/table/header.rb +11 -0
- data/lib/protos/table/row.rb +11 -0
- data/lib/protos/table.rb +48 -0
- data/lib/protos/theme.rb +76 -0
- data/lib/protos/timeline/center.rb +19 -0
- data/lib/protos/timeline/item.rb +11 -0
- data/lib/protos/timeline/left.rb +19 -0
- data/lib/protos/timeline/right.rb +19 -0
- data/lib/protos/timeline.rb +38 -0
- data/lib/protos/token_list.rb +41 -0
- data/lib/protos/types.rb +32 -0
- data/lib/protos/typography/heading.rb +44 -0
- data/lib/protos/typography/inline_link.rb +24 -0
- data/lib/protos/typography/paragraph.rb +22 -0
- data/lib/protos/typography.rb +29 -0
- data/lib/protos/version.rb +5 -0
- data/lib/protos.rb +94 -0
- data/protos.gemspec +45 -0
- metadata +180 -0
data/lib/protos/list.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class List < Component
|
5
|
+
option :ordered, Types::Bool, default: -> { false }, reader: false
|
6
|
+
|
7
|
+
def template(&block)
|
8
|
+
send(element, **attrs, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def item(...)
|
12
|
+
Item.new(...)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def css
|
18
|
+
{
|
19
|
+
container: tokens(
|
20
|
+
"join",
|
21
|
+
"join-vertical"
|
22
|
+
)
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def element
|
27
|
+
@ordered ? :ol : :ul
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Modal
|
5
|
+
class Dialog < Component
|
6
|
+
def template(&block)
|
7
|
+
dialog(**attrs) do
|
8
|
+
div(class: css[:modal], &block)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def theme
|
15
|
+
{
|
16
|
+
container: tokens("modal", "modal-bottom", "sm:modal-middle"),
|
17
|
+
modal: tokens("modal-box", "flex", "flex-col", "gap-xs")
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def attrs
|
22
|
+
@attrs ||= build_attrs(
|
23
|
+
{
|
24
|
+
data: { "protos--modal-target": "modal" }
|
25
|
+
}
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Modal
|
5
|
+
class Trigger < Component
|
6
|
+
def template(&block)
|
7
|
+
button(**attrs, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def default_attrs
|
13
|
+
{
|
14
|
+
data: { action: "protos--modal#open" }
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/protos/modal.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Modal < Protos::Component
|
5
|
+
def template(&block)
|
6
|
+
div(**attrs, class: css[:container], &block)
|
7
|
+
end
|
8
|
+
|
9
|
+
def close_button(...)
|
10
|
+
CloseButton.new(...)
|
11
|
+
end
|
12
|
+
|
13
|
+
def dialog(...)
|
14
|
+
Dialog.new(...)
|
15
|
+
end
|
16
|
+
|
17
|
+
def trigger(...)
|
18
|
+
Trigger.new(...)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def default_attrs
|
24
|
+
{
|
25
|
+
data: {
|
26
|
+
controller: "protos--modal"
|
27
|
+
}
|
28
|
+
}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Popover
|
5
|
+
class Content < Component
|
6
|
+
def template(&block)
|
7
|
+
div(**attrs, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def theme
|
13
|
+
{
|
14
|
+
container: tokens("dropdown-content", "z-10")
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Popover < Component
|
5
|
+
# DOCS: Like a dropdown, but instead of a list of menu items, its just
|
6
|
+
# a rendered block
|
7
|
+
|
8
|
+
PositionTypes = Types::Coercible::Symbol.enum(
|
9
|
+
:top,
|
10
|
+
:bottom,
|
11
|
+
:left,
|
12
|
+
:right,
|
13
|
+
:start,
|
14
|
+
:end
|
15
|
+
)
|
16
|
+
|
17
|
+
option :position,
|
18
|
+
type: PositionTypes,
|
19
|
+
default: -> { :bottom },
|
20
|
+
reader: false
|
21
|
+
option :hover, type: Types::Bool, default: -> { false }
|
22
|
+
|
23
|
+
def template(&block)
|
24
|
+
details(**attrs, &block)
|
25
|
+
end
|
26
|
+
|
27
|
+
def content(...)
|
28
|
+
Content.new(...)
|
29
|
+
end
|
30
|
+
|
31
|
+
def trigger(...)
|
32
|
+
Trigger.new(...)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def position
|
38
|
+
{
|
39
|
+
bottom: "dropdown-bottom",
|
40
|
+
top: "dropdown-top",
|
41
|
+
left: "dropdown-left",
|
42
|
+
right: "dropdown-right",
|
43
|
+
end: "dropdown-end",
|
44
|
+
start: "dropdown-start"
|
45
|
+
}.fetch(@position)
|
46
|
+
end
|
47
|
+
|
48
|
+
def theme
|
49
|
+
{
|
50
|
+
container: tokens("dropdown", position)
|
51
|
+
}
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Table
|
5
|
+
class Caption < Component
|
6
|
+
def template(&block)
|
7
|
+
caption(**attrs, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def theme
|
13
|
+
{
|
14
|
+
container: tokens("caption-bottom", "p-sm")
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/protos/table.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Table < Component
|
5
|
+
def template(&block)
|
6
|
+
div(**attrs) do
|
7
|
+
table(class: css[:table], &block)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def body(...)
|
12
|
+
Body.new(...)
|
13
|
+
end
|
14
|
+
|
15
|
+
def caption(...)
|
16
|
+
Caption.new(...)
|
17
|
+
end
|
18
|
+
|
19
|
+
def cell(...)
|
20
|
+
Cell.new(...)
|
21
|
+
end
|
22
|
+
|
23
|
+
def footer(...)
|
24
|
+
Footer.new(...)
|
25
|
+
end
|
26
|
+
|
27
|
+
def head(...)
|
28
|
+
Head.new(...)
|
29
|
+
end
|
30
|
+
|
31
|
+
def header(...)
|
32
|
+
Header.new(...)
|
33
|
+
end
|
34
|
+
|
35
|
+
def row(...)
|
36
|
+
Row.new(...)
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def theme
|
42
|
+
{
|
43
|
+
container: tokens("w-full", "overflow-x-auto"),
|
44
|
+
table: tokens("table")
|
45
|
+
}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/protos/theme.rb
ADDED
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Theme
|
5
|
+
def initialize(theme = {}, **kwargs)
|
6
|
+
@theme = theme.merge(kwargs)
|
7
|
+
end
|
8
|
+
|
9
|
+
def [](key)
|
10
|
+
@theme[key]
|
11
|
+
end
|
12
|
+
|
13
|
+
def key?(key)
|
14
|
+
@theme.key?(key)
|
15
|
+
end
|
16
|
+
|
17
|
+
def add(key, value)
|
18
|
+
current_tokens = parse(@theme.fetch(key, ""))
|
19
|
+
new_tokens = parse(value)
|
20
|
+
tokens = current_tokens + new_tokens
|
21
|
+
|
22
|
+
@theme[key] = tokens.to_s
|
23
|
+
end
|
24
|
+
|
25
|
+
def remove(key, value)
|
26
|
+
current_tokens = parse(@theme.fetch(key, ""))
|
27
|
+
removable_tokens = parse(value)
|
28
|
+
tokens = current_tokens - removable_tokens
|
29
|
+
|
30
|
+
@theme[key] = tokens.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
def set(key, value)
|
34
|
+
if value.is_a?(Hash)
|
35
|
+
@theme[key] = value
|
36
|
+
else
|
37
|
+
tokens = parse(value)
|
38
|
+
@theme[key] = tokens.to_s
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def merge(hash)
|
43
|
+
hash ||= {}
|
44
|
+
|
45
|
+
tap do
|
46
|
+
hash.each_key do |key|
|
47
|
+
if key?(key)
|
48
|
+
add(key, hash[key])
|
49
|
+
elsif negation?(key)
|
50
|
+
no_bang = key.to_s[1..].to_sym
|
51
|
+
remove(no_bang, hash[key])
|
52
|
+
elsif override?(key)
|
53
|
+
no_bang = key.to_s.chomp("!").to_sym
|
54
|
+
set(no_bang, hash[key])
|
55
|
+
else
|
56
|
+
set(key, hash[key])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def parse(value)
|
65
|
+
TokenList.parse(value)
|
66
|
+
end
|
67
|
+
|
68
|
+
def negation?(key)
|
69
|
+
key.to_s.start_with?("!")
|
70
|
+
end
|
71
|
+
|
72
|
+
def override?(key)
|
73
|
+
key.to_s.end_with?("!")
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Timeline
|
5
|
+
class Center < Component
|
6
|
+
def template(&block)
|
7
|
+
div(**attrs, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def theme
|
13
|
+
{
|
14
|
+
container: tokens("timeline-middle")
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Timeline
|
5
|
+
class Left < Component
|
6
|
+
def template(&block)
|
7
|
+
div(**attrs, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def theme
|
13
|
+
{
|
14
|
+
container: tokens("timeline-start")
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Timeline
|
5
|
+
class Right < Component
|
6
|
+
def template(&block)
|
7
|
+
div(**attrs, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def theme
|
13
|
+
{
|
14
|
+
container: tokens("timeline-end")
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class Timeline < Component
|
5
|
+
option :vertical, type: Types::Bool, default: -> { false }
|
6
|
+
|
7
|
+
def template(&block)
|
8
|
+
ul(**attrs, &block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def item(...)
|
12
|
+
Item.new(...)
|
13
|
+
end
|
14
|
+
|
15
|
+
def left(...)
|
16
|
+
Left.new(...)
|
17
|
+
end
|
18
|
+
|
19
|
+
def center(...)
|
20
|
+
Center.new(...)
|
21
|
+
end
|
22
|
+
|
23
|
+
def right(...)
|
24
|
+
Right.new(...)
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def css
|
30
|
+
{
|
31
|
+
container: tokens(
|
32
|
+
"timeline",
|
33
|
+
vertical: "timeline-vertical"
|
34
|
+
)
|
35
|
+
}
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
class TokenList
|
5
|
+
def self.parse(input)
|
6
|
+
case input
|
7
|
+
when String then new(input.split)
|
8
|
+
when Array then new(input)
|
9
|
+
else raise ArgumentError, "Invalid input: #{input.inspect}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :tokens
|
14
|
+
|
15
|
+
def initialize(tokens)
|
16
|
+
@tokens = Set.new(tokens)
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
@tokens.to_a.join(" ")
|
21
|
+
end
|
22
|
+
|
23
|
+
def -(other)
|
24
|
+
other = TokenList.parse(other) unless other.is_a?(TokenList)
|
25
|
+
self.class.new(@tokens - other.tokens)
|
26
|
+
end
|
27
|
+
|
28
|
+
def +(other)
|
29
|
+
other = TokenList.parse(other) unless other.is_a?(TokenList)
|
30
|
+
self.class.new(@tokens + other.tokens)
|
31
|
+
end
|
32
|
+
|
33
|
+
def remove(token)
|
34
|
+
@tokens.delete(token)
|
35
|
+
end
|
36
|
+
|
37
|
+
def add(token)
|
38
|
+
@tokens.add(token)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/protos/types.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
module Types
|
5
|
+
include Dry.Types()
|
6
|
+
|
7
|
+
MaskShapes = Types::Coercible::Symbol.enum(
|
8
|
+
:none,
|
9
|
+
:squircle,
|
10
|
+
:heart,
|
11
|
+
:hexagon,
|
12
|
+
:hexagon2,
|
13
|
+
:decagon,
|
14
|
+
:pentagon,
|
15
|
+
:diamond,
|
16
|
+
:square,
|
17
|
+
:circle,
|
18
|
+
:parallelogram,
|
19
|
+
:parallelogram2,
|
20
|
+
:parallelogram3,
|
21
|
+
:parallelogram4,
|
22
|
+
:star,
|
23
|
+
:star2,
|
24
|
+
:triangle,
|
25
|
+
:triangle2,
|
26
|
+
:triangle3,
|
27
|
+
:triangle4,
|
28
|
+
:half1,
|
29
|
+
:half2
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
module Typography
|
5
|
+
class Heading < Protos::Component
|
6
|
+
SizeTypes = Types::Coercible::Symbol.enum(:xs, :sm, :md, :lg, :xl)
|
7
|
+
LevelTypes = Types::Integer.enum(1, 2, 3, 4, 5, 6)
|
8
|
+
|
9
|
+
option :size, type: SizeTypes, default: -> { "md" }, reader: false
|
10
|
+
option :level, type: LevelTypes, default: -> { 1 }, reader: false
|
11
|
+
|
12
|
+
def template(&block)
|
13
|
+
send(element, **attrs, &block)
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def theme
|
19
|
+
{
|
20
|
+
container: tokens(
|
21
|
+
size,
|
22
|
+
"scroll-m-20",
|
23
|
+
"tracking-tight",
|
24
|
+
"transition-colors"
|
25
|
+
)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
def size
|
30
|
+
{
|
31
|
+
xs: "text-lg font-medium",
|
32
|
+
sm: "text-xl font-medium",
|
33
|
+
md: "text-2xl font-semibold",
|
34
|
+
lg: "text-3xl font-semibold md:text-4xl",
|
35
|
+
xl: "text-4xl font-bold md:text-5xl"
|
36
|
+
}.fetch(@size.to_sym)
|
37
|
+
end
|
38
|
+
|
39
|
+
def element
|
40
|
+
%i[h1 h2 h3 h4 h5 h6][@level - 1]
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Protos
|
4
|
+
module Typography
|
5
|
+
class InlineLink < Component
|
6
|
+
def template(&block)
|
7
|
+
a(**attrs, &block)
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def theme
|
13
|
+
{
|
14
|
+
container: tokens(
|
15
|
+
"font-medium",
|
16
|
+
"hover:underline",
|
17
|
+
"underline-offset-4",
|
18
|
+
"cursor-pointer"
|
19
|
+
)
|
20
|
+
}
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|