ariadne_view_components 0.0.10-x86_64-linux
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/LICENSE.txt +49 -0
- data/README.md +73 -0
- data/app/assets/config/manifest.js +2 -0
- data/app/assets/javascripts/ariadne-form-with.d.ts +20 -0
- data/app/assets/javascripts/ariadne-form.d.ts +22 -0
- data/app/assets/javascripts/ariadne.d.ts +1 -0
- data/app/assets/javascripts/ariadne_view_components.js +8 -0
- data/app/assets/javascripts/ariadne_view_components.js.map +1 -0
- data/app/assets/javascripts/clipboard-copy-component.d.ts +4 -0
- data/app/assets/javascripts/comment-component.d.ts +13 -0
- data/app/assets/javascripts/rich-text-area-component.d.ts +4 -0
- data/app/assets/javascripts/slideover-component.d.ts +9 -0
- data/app/assets/javascripts/time-ago-component.d.ts +1 -0
- data/app/assets/javascripts/time_ago_component.d.ts +1 -0
- data/app/assets/javascripts/tooltip-component.d.ts +24 -0
- data/app/assets/stylesheets/ariadne_view_components.css +6 -0
- data/app/assets/stylesheets/prosemirror.css +323 -0
- data/app/assets/stylesheets/tooltip-component.css +37 -0
- data/app/components/ariadne/ariadne-form.ts +96 -0
- data/app/components/ariadne/ariadne.ts +20 -0
- data/app/components/ariadne/base_button.rb +61 -0
- data/app/components/ariadne/base_component.rb +37 -0
- data/app/components/ariadne/blankslate_component.html.erb +26 -0
- data/app/components/ariadne/blankslate_component.rb +146 -0
- data/app/components/ariadne/body_component.rb +30 -0
- data/app/components/ariadne/button_component.html.erb +4 -0
- data/app/components/ariadne/button_component.rb +157 -0
- data/app/components/ariadne/clipboard-copy-component.ts +19 -0
- data/app/components/ariadne/clipboard_copy_component.html.erb +9 -0
- data/app/components/ariadne/clipboard_copy_component.rb +90 -0
- data/app/components/ariadne/comment-component.ts +55 -0
- data/app/components/ariadne/comment_component.html.erb +22 -0
- data/app/components/ariadne/comment_component.rb +57 -0
- data/app/components/ariadne/component.rb +128 -0
- data/app/components/ariadne/container_component.html.erb +3 -0
- data/app/components/ariadne/container_component.rb +25 -0
- data/app/components/ariadne/content.rb +12 -0
- data/app/components/ariadne/counter_component.rb +100 -0
- data/app/components/ariadne/flash_component.html.erb +31 -0
- data/app/components/ariadne/flash_component.rb +125 -0
- data/app/components/ariadne/flex_component.rb +49 -0
- data/app/components/ariadne/footer_component.html.erb +7 -0
- data/app/components/ariadne/footer_component.rb +23 -0
- data/app/components/ariadne/grid_component.html.erb +26 -0
- data/app/components/ariadne/grid_component.rb +66 -0
- data/app/components/ariadne/header_component.html.erb +29 -0
- data/app/components/ariadne/header_component.rb +114 -0
- data/app/components/ariadne/heading_component.rb +49 -0
- data/app/components/ariadne/heroicon_component.html.erb +4 -0
- data/app/components/ariadne/heroicon_component.rb +129 -0
- data/app/components/ariadne/image_component.rb +53 -0
- data/app/components/ariadne/inline_flex_component.html.erb +5 -0
- data/app/components/ariadne/inline_flex_component.rb +65 -0
- data/app/components/ariadne/link_component.rb +65 -0
- data/app/components/ariadne/list_component.html.erb +15 -0
- data/app/components/ariadne/list_component.rb +68 -0
- data/app/components/ariadne/main_component.rb +32 -0
- data/app/components/ariadne/narrow_container_component.html.erb +3 -0
- data/app/components/ariadne/narrow_container_component.rb +30 -0
- data/app/components/ariadne/panel_bar_component.html.erb +20 -0
- data/app/components/ariadne/panel_bar_component.rb +79 -0
- data/app/components/ariadne/pill_component.html.erb +3 -0
- data/app/components/ariadne/pill_component.rb +30 -0
- data/app/components/ariadne/rich-text-area-component.ts +32 -0
- data/app/components/ariadne/rich_text_area_component.html.erb +6 -0
- data/app/components/ariadne/rich_text_area_component.rb +35 -0
- data/app/components/ariadne/slideover-component.ts +26 -0
- data/app/components/ariadne/slideover_component.html.erb +11 -0
- data/app/components/ariadne/slideover_component.rb +81 -0
- data/app/components/ariadne/tab_bar_component.html.erb +3 -0
- data/app/components/ariadne/tab_bar_component.rb +45 -0
- data/app/components/ariadne/tab_component.html.erb +7 -0
- data/app/components/ariadne/tab_component.rb +43 -0
- data/app/components/ariadne/text.rb +25 -0
- data/app/components/ariadne/time-ago-component.ts +1 -0
- data/app/components/ariadne/time_ago_component.rb +56 -0
- data/app/components/ariadne/timeline_component.html.erb +19 -0
- data/app/components/ariadne/timeline_component.rb +34 -0
- data/app/components/ariadne/tooltip-component.ts +57 -0
- data/app/components/ariadne/tooltip_component.html.erb +4 -0
- data/app/components/ariadne/tooltip_component.rb +108 -0
- data/app/lib/ariadne/action_view_extensions/form_helper.rb +26 -0
- data/app/lib/ariadne/audited/dsl.rb +32 -0
- data/app/lib/ariadne/class_name_helper.rb +22 -0
- data/app/lib/ariadne/fetch_or_fallback_helper.rb +102 -0
- data/app/lib/ariadne/form_builder.rb +71 -0
- data/app/lib/ariadne/icon_helper.rb +47 -0
- data/app/lib/ariadne/join_style_arguments_helper.rb +14 -0
- data/app/lib/ariadne/logger_helper.rb +23 -0
- data/app/lib/ariadne/status/dsl.rb +41 -0
- data/app/lib/ariadne/tab_nav_helper.rb +35 -0
- data/app/lib/ariadne/tabbed_component_helper.rb +39 -0
- data/app/lib/ariadne/test_selector_helper.rb +20 -0
- data/app/lib/ariadne/underline_nav_helper.rb +44 -0
- data/app/lib/ariadne/view_helper.rb +22 -0
- data/exe/tailwindcss +21 -0
- data/exe/x86_64-linux/tailwindcss +0 -0
- data/lib/ariadne/view_components/commands.rb +90 -0
- data/lib/ariadne/view_components/constants.rb +53 -0
- data/lib/ariadne/view_components/engine.rb +75 -0
- data/lib/ariadne/view_components/linters.rb +3 -0
- data/lib/ariadne/view_components/statuses.rb +14 -0
- data/lib/ariadne/view_components/upstream.rb +20 -0
- data/lib/ariadne/view_components/version.rb +7 -0
- data/lib/ariadne/view_components.rb +61 -0
- data/lib/rubocop/config/default.yml +8 -0
- data/lib/rubocop/cop/ariadne/base_cop.rb +26 -0
- data/lib/rubocop/cop/ariadne/no_tag_memoize.rb +44 -0
- data/lib/rubocop/cop/ariadne.rb +3 -0
- data/lib/tasks/ariadne_view_components.rake +48 -0
- data/lib/tasks/build.rake +30 -0
- data/lib/tasks/coverage.rake +19 -0
- data/lib/tasks/custom_utilities.yml +310 -0
- data/lib/tasks/docs.rake +524 -0
- data/lib/tasks/helpers/ast_processor.rb +44 -0
- data/lib/tasks/helpers/ast_traverser.rb +77 -0
- data/lib/tasks/static.rake +15 -0
- data/lib/yard/docs_helper.rb +83 -0
- data/lib/yard/renders_many_handler.rb +19 -0
- data/lib/yard/renders_one_handler.rb +19 -0
- data/static/arguments.yml +619 -0
- data/static/assets/view-components.svg +18 -0
- data/static/audited_at.json +38 -0
- data/static/classes.yml +291 -0
- data/static/constants.json +426 -0
- data/static/statuses.json +38 -0
- data/static/tailwindcss.yml +727 -0
- data/tailwind.config.js +65 -0
- metadata +264 -0
@@ -0,0 +1,114 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# Represents the top navigation bar on every page.
|
5
|
+
class HeaderComponent < Ariadne::Component
|
6
|
+
DEFAULT_CLASSES = "ariadne-sticky ariadne-top-0 ariadne-z-50 ariadne-px-4 ariadne-py-5 ariadne-bg-white ariadne-shadow-sm shadow-slate-900/5 ariadne-transition ariadne-duration-500"
|
7
|
+
# ariadne-flex ariadne-flex-wrap ariadne-items-center ariadne-justify-between ariadne-bg-white dark:ariadne-shadow-none dark:ariadne-bg-transparent
|
8
|
+
LINK_CLASSES = "ariadne-rounded-lg ariadne-py-1 ariadne-px-2 text-slate-700 hover:bg-slate-100 hover:text-slate-900"
|
9
|
+
|
10
|
+
DEFAULT_TEXT_LOGO_CLASSES = "ariadne-flex ariadne-items-center ariadne-font-bold ariadne-text-xl"
|
11
|
+
DEFAULT_IMAGE_LOGO_CLASSES = "ariadne-h-10 ariadne-w-auto"
|
12
|
+
|
13
|
+
# Leading visuals at the far left of the header. You can pass either
|
14
|
+
# `src` or `as_text` but not both.
|
15
|
+
#
|
16
|
+
# @param href [String] Where the logo should link to.
|
17
|
+
# @param src [String] The URL of the image logo.
|
18
|
+
# @param alt [String] Alt text for accessibility.
|
19
|
+
# @param as_text [Boolean] The text to display
|
20
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
21
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
22
|
+
renders_one :logo, lambda { |href: nil, src: nil, alt: nil, as_text: false, classes: "", attributes: {}|
|
23
|
+
@href = href
|
24
|
+
if as_text.present?
|
25
|
+
actual_classes = class_names(DEFAULT_TEXT_LOGO_CLASSES, classes)
|
26
|
+
@text_logo = Ariadne::Text.new(tag: :span, classes: actual_classes, attributes: attributes)
|
27
|
+
else
|
28
|
+
actual_classes = class_names(DEFAULT_IMAGE_LOGO_CLASSES, classes)
|
29
|
+
actual_attributes = { width: 40, height: 40 }.merge(attributes)
|
30
|
+
@image_logo = Ariadne::ImageComponent.new(src: src, alt: alt, classes: actual_classes, attributes: actual_attributes)
|
31
|
+
end
|
32
|
+
}
|
33
|
+
|
34
|
+
# Text within the header, representing navigation.
|
35
|
+
#
|
36
|
+
# @param tag [String, Symbol] The tag to use for the link.
|
37
|
+
# @param href [String] The link destination.
|
38
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
39
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
40
|
+
DEFAULT_NAV_LINK_CLASSES = "ariadne-inline-block ariadne-rounded-lg ariadne-py-1 ariadne-px-2 ariadne-text-sm text-slate-700 hover:bg-slate-100 hover:text-slate-900"
|
41
|
+
renders_many :navigation_links, lambda { |tag: Ariadne::LinkComponent::DEFAULT_TAG, href:, classes: "", attributes: {}|
|
42
|
+
actual_classes = class_names(DEFAULT_NAV_LINK_CLASSES, classes)
|
43
|
+
Ariadne::LinkComponent.new(tag: tag, href: href, classes: actual_classes, attributes: attributes)
|
44
|
+
}
|
45
|
+
|
46
|
+
# Text within the header, representing actions.
|
47
|
+
#
|
48
|
+
# @param tag [String, Symbol] The tag to use for the link.
|
49
|
+
# @param href [String] The link destination.
|
50
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
51
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
52
|
+
renders_many :action_links, lambda { |tag: Ariadne::LinkComponent::DEFAULT_TAG, href:, classes: "", attributes: {}|
|
53
|
+
actual_classes = class_names(DEFAULT_NAV_LINK_CLASSES, classes)
|
54
|
+
Ariadne::LinkComponent.new(tag: tag, href: href, classes: actual_classes, attributes: attributes)
|
55
|
+
}
|
56
|
+
|
57
|
+
# Text within the header, representing a signup.
|
58
|
+
#
|
59
|
+
# @param tag [String, Symbol] The tag to use for the link.
|
60
|
+
# @param href [String] The link destination.
|
61
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
62
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
63
|
+
DEFAULT_SIGNUP_LINK_CLASSES = "group ariadne-inline-flex ariadne-items-center ariadne-justify-center ariadne-rounded-full ariadne-py-2 ariadne-px-4 ariadne-text-sm ariadne-font-semibold focus:ariadne-outline-none focus-visible:outline-2 focus-visible:outline-offset-2"
|
64
|
+
renders_one :signup_link, lambda { |tag: Ariadne::LinkComponent::DEFAULT_TAG, href:, classes: "", attributes: {}|
|
65
|
+
actual_classes = class_names(DEFAULT_SIGNUP_LINK_CLASSES, classes)
|
66
|
+
Ariadne::LinkComponent.new(tag: tag, href: href, classes: actual_classes, attributes: attributes)
|
67
|
+
}
|
68
|
+
|
69
|
+
DEFAULT_PROFILE_LINK_CLASSES = "group ariadne-inline-flex ariadne-items-center ariadne-justify-center ariadne-rounded-full ariadne-py-2 ariadne-px-4 ariadne-text-sm ariadne-font-semibold focus:ariadne-outline-none focus-visible:outline-2 focus-visible:outline-offset-2"
|
70
|
+
renders_one :profile_link, lambda { |tag: Ariadne::LinkComponent::DEFAULT_TAG, href:, classes: "", attributes: {}|
|
71
|
+
actual_classes = class_names(DEFAULT_PROFILE_LINK_CLASSES, classes)
|
72
|
+
Ariadne::LinkComponent.new(tag: tag, href: href, classes: actual_classes, attributes: attributes)
|
73
|
+
}
|
74
|
+
|
75
|
+
# @example Basic example
|
76
|
+
#
|
77
|
+
# <%= render(Ariadne::HeaderComponent.new) do |header| %>
|
78
|
+
# <%= header.logo(as_text: true) { "GitHub" } %>
|
79
|
+
# <%= header.navigation_link(href: "#features") { "Features" } %>
|
80
|
+
# <%= header.login_link(href: "/login") { "Login" } %>
|
81
|
+
# <% end %>
|
82
|
+
#
|
83
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
84
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
85
|
+
def initialize(classes: "", attributes: {})
|
86
|
+
@classes = class_names(
|
87
|
+
DEFAULT_CLASSES,
|
88
|
+
classes
|
89
|
+
)
|
90
|
+
|
91
|
+
@attributes = attributes
|
92
|
+
end
|
93
|
+
|
94
|
+
private def has_logo?
|
95
|
+
logo.present?
|
96
|
+
end
|
97
|
+
|
98
|
+
private def has_text_logo?
|
99
|
+
logo.present? && @text_logo.present?
|
100
|
+
end
|
101
|
+
|
102
|
+
private def has_image_logo?
|
103
|
+
logo.present? && @image_logo.present?
|
104
|
+
end
|
105
|
+
|
106
|
+
private def has_signup_link?
|
107
|
+
signup_link.present?
|
108
|
+
end
|
109
|
+
|
110
|
+
private def has_profile_link?
|
111
|
+
profile_link.present?
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# `Heading` should be used to communicate page organization and hierarchy.
|
5
|
+
#
|
6
|
+
# - Set tag to one of `:h1`, `:h2`, `:h3`, `:h4`, `:h5`, `:h6` based on what is appropriate for the page context.
|
7
|
+
# - Use `Heading` as the title of a section or sub section.
|
8
|
+
# - Do not use `Heading` for styling alone. For simply styling text, consider using <%= link_to_component(Ariadne::Text) %> with relevant <%= link_to_typography_docs %>
|
9
|
+
# such as `font_size` and `font_weight`.
|
10
|
+
# - Do not jump heading levels. For instance, do not follow a `<h1>` with an `<h3>`. Heading levels should increase by one in ascending order.
|
11
|
+
#
|
12
|
+
# @accessibility
|
13
|
+
# While sighted users rely on visual cues such as font size changes to determine what the heading is, assistive technology users rely on programatic cues that can be read out.
|
14
|
+
# When text on a page is visually implied to be a heading, ensure that it is coded as a heading. Additionally, visually implied heading level and coded heading level should be
|
15
|
+
# consistent. [See WCAG success criteria: 1.3.1: Info and Relationships](https://www.w3.org/WAI/WCAG21/Understanding/info-and-relationships.html)
|
16
|
+
#
|
17
|
+
# Headings allow assistive technology users to quickly navigate around a page. Navigation to text that is not meant to be a heading can be a confusing experience.
|
18
|
+
# <%= link_to_heading_practices %>
|
19
|
+
class HeadingComponent < Ariadne::Component
|
20
|
+
TAG_OPTIONS = [:h1, :h2, :h3, :h4, :h5, :h6].freeze
|
21
|
+
|
22
|
+
TAG_TO_CLASSES = {
|
23
|
+
h1: "ariadne-font-bold ariadne-leading-7 sm:ariadne-text-3xl",
|
24
|
+
h2: "ariadne-text-3xl ariadne-font-extrabold",
|
25
|
+
h3: "ariadne-text-2xl ariadne-font-extrabold",
|
26
|
+
}
|
27
|
+
# @example Default
|
28
|
+
# <%= render(Ariadne::HeadingComponent.new(tag: :h1)) { "H1 Text" } %>
|
29
|
+
# <%= render(Ariadne::HeadingComponent.new(tag: :h2)) { "H2 Text" } %>
|
30
|
+
# <%= render(Ariadne::HeadingComponent.new(tag: :h3)) { "H3 Text" } %>
|
31
|
+
# <%= render(Ariadne::HeadingComponent.new(tag: :h4)) { "H4 Text" } %>
|
32
|
+
# <%= render(Ariadne::HeadingComponent.new(tag: :h5)) { "H5 Text" } %>
|
33
|
+
# <%= render(Ariadne::HeadingComponent.new(tag: :h6)) { "H6 Text" } %>
|
34
|
+
#
|
35
|
+
# @param tag [String] <%= one_of(Ariadne::HeadingComponent::TAG_OPTIONS) %>
|
36
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
37
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
38
|
+
def initialize(tag: nil, classes: "", attributes: {})
|
39
|
+
@tag = fetch_or_raise(TAG_OPTIONS, tag)
|
40
|
+
@attributes = attributes
|
41
|
+
|
42
|
+
@classes = class_names(*TAG_TO_CLASSES[tag], classes)
|
43
|
+
end
|
44
|
+
|
45
|
+
def call
|
46
|
+
render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) { content }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,4 @@
|
|
1
|
+
<%= render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) do %>
|
2
|
+
<%= @icon.path.html_safe %>
|
3
|
+
<% end %>
|
4
|
+
<%= render(Ariadne::BaseComponent.new(tag: :span, classes: @text_classes, attributes: @text_attributes)) { content } if content.present? %>
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "heroicons_helper"
|
4
|
+
|
5
|
+
module Ariadne
|
6
|
+
# `Heroicon` renders an <%= link_to_heroicons %> with <%= link_to_attributes_docs %>.
|
7
|
+
# `Heroicon` can also be rendered with the `heroicon` helper.
|
8
|
+
class HeroiconComponent < Ariadne::Component
|
9
|
+
DEFAULT_TEXT_CLASSES = "ariadne-pl-2"
|
10
|
+
|
11
|
+
include IconHelper
|
12
|
+
include HeroiconsHelper
|
13
|
+
|
14
|
+
SIZE_DEFAULT = :sm
|
15
|
+
SIZE_MEDIUM = :md
|
16
|
+
SIZE_LARGE = :lg
|
17
|
+
|
18
|
+
SIZE_MAPPINGS = {
|
19
|
+
SIZE_DEFAULT => 16,
|
20
|
+
SIZE_MEDIUM => 24,
|
21
|
+
SIZE_LARGE => 128,
|
22
|
+
}.freeze
|
23
|
+
SIZE_OPTIONS = SIZE_MAPPINGS.keys
|
24
|
+
|
25
|
+
PRELOADED_ICONS = [
|
26
|
+
{ name: "bell",
|
27
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
28
|
+
{ name: "check",
|
29
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
30
|
+
{ name: "chevron-down",
|
31
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
32
|
+
{ name: "clipboard",
|
33
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
34
|
+
{ name: "clock",
|
35
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
36
|
+
{ name: "information-circle",
|
37
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
38
|
+
{ name: "dots-horizontal",
|
39
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
40
|
+
{ name: "link",
|
41
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
42
|
+
{ name: "lock-closed",
|
43
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
44
|
+
{ name: "mail",
|
45
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
46
|
+
{ name: "menu",
|
47
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
48
|
+
{ name: "pencil",
|
49
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
50
|
+
{ name: "plus-sm",
|
51
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
52
|
+
{ name: "question-mark-circle",
|
53
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
54
|
+
{ name: "search",
|
55
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
56
|
+
{ name: "search",
|
57
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
58
|
+
{ name: "trash",
|
59
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
60
|
+
{ name: "x-mark",
|
61
|
+
variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, },
|
62
|
+
].freeze
|
63
|
+
|
64
|
+
# @example Default
|
65
|
+
# <%= render(Ariadne::HeroiconComponent.new(icon: :check, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE)) %>
|
66
|
+
# <%= render(Ariadne::HeroiconComponent.new(icon: :check, variant: HeroiconsHelper::Icon::VARIANT_SOLID)) %>
|
67
|
+
#
|
68
|
+
# @example Medium
|
69
|
+
# <%= render(Ariadne::HeroiconComponent.new(icon: :"user-group", variant: HeroiconsHelper::Icon::VARIANT_OUTLINE, size: :md)) %>
|
70
|
+
#
|
71
|
+
# @example Helper
|
72
|
+
# <%= ariadne_heroicon(icon: :check, variant: HeroiconsHelper::Icon::VARIANT_OUTLINE) %>
|
73
|
+
#
|
74
|
+
# @param tag [Symbol, String] The rendered tag name
|
75
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
76
|
+
# @param icon [Symbol, String] Name of <%= link_to_heroicons %> to use.
|
77
|
+
# @param variant [String] <%= one_of(HeroiconsHelper::Icon::VALID_VARIANTS, sort: false) %>
|
78
|
+
# @param size [Symbol] <%= one_of(Ariadne::HeroiconComponent::SIZE_MAPPINGS, sort: false) %>
|
79
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
80
|
+
# @param text_classes [String] <%= link_to_classes_docs %>
|
81
|
+
# @param text_attributes [Hash] <%= link_to_attributes_docs %>
|
82
|
+
def initialize(tag: :svg, icon:, variant:, size: SIZE_DEFAULT, classes: "", attributes: {}, text_classes: "", text_attributes: {})
|
83
|
+
@tag = check_incoming_tag(:svg, tag)
|
84
|
+
|
85
|
+
check_icon_presence!(icon, variant)
|
86
|
+
|
87
|
+
@attributes = attributes
|
88
|
+
@attributes[:aria] ||= {}
|
89
|
+
|
90
|
+
if @attributes[:aria][:label] || @attributes[:"aria-label"]
|
91
|
+
@attributes[:role] = "img"
|
92
|
+
else
|
93
|
+
@attributes[:aria][:hidden] = true
|
94
|
+
end
|
95
|
+
|
96
|
+
# Don't allow sizes under 16px
|
97
|
+
if attributes[:height].present? && attributes[:height].to_i < 16 || attributes[:width].present? && attributes[:width].to_i < 16
|
98
|
+
attributes.delete(:height)
|
99
|
+
attributes.delete(:width)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Filter out classify options to prevent them from becoming invalid html attributes.
|
103
|
+
# Note height and width are both classify options and valid html attributes.
|
104
|
+
attributes = {
|
105
|
+
height: @attributes[:height] || SIZE_MAPPINGS[fetch_or_raise(SIZE_OPTIONS, size)],
|
106
|
+
width: @attributes[:width],
|
107
|
+
}
|
108
|
+
|
109
|
+
@icon = heroicon(icon, variant: variant, **attributes)
|
110
|
+
|
111
|
+
@classes = class_names(
|
112
|
+
@icon.attributes[:class],
|
113
|
+
classes
|
114
|
+
)
|
115
|
+
@attributes.merge!(@icon.attributes.except(:class, :"aria-hidden"))
|
116
|
+
|
117
|
+
@text_classes = class_names(DEFAULT_TEXT_CLASSES, text_classes)
|
118
|
+
@text_attributes = text_attributes
|
119
|
+
end
|
120
|
+
|
121
|
+
class << self
|
122
|
+
def _after_compile
|
123
|
+
HeroiconsHelper::Cache.preload!(PRELOADED_ICONS) do |found, icon|
|
124
|
+
HeroiconComponent.new(icon: icon[:name], variant: icon[:variant]) unless found
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# Use `Image` to render images.
|
5
|
+
#
|
6
|
+
# @accessibility
|
7
|
+
# Always provide a meaningful `alt`.
|
8
|
+
class ImageComponent < Ariadne::Component
|
9
|
+
DEFAULT_TAG = :img
|
10
|
+
|
11
|
+
# @example Default
|
12
|
+
#
|
13
|
+
# <%= render(Ariadne::ImageComponent.new(src: "https://github.com/github.png", alt: "GitHub")) %>
|
14
|
+
#
|
15
|
+
# @example Helper
|
16
|
+
#
|
17
|
+
# <%= ariadne_image(src: "https://github.com/github.png", alt: "GitHub") %>
|
18
|
+
#
|
19
|
+
# @example Lazy loading
|
20
|
+
#
|
21
|
+
# <%= render(Ariadne::ImageComponent.new(src: "https://github.com/github.png", alt: "GitHub", lazy: true)) %>
|
22
|
+
#
|
23
|
+
# @example Custom size
|
24
|
+
#
|
25
|
+
# <%= render(Ariadne::ImageComponent.new(src: "https://github.com/github.png", alt: "GitHub", attributes: { height: 100, width: 100 })) %>
|
26
|
+
#
|
27
|
+
# @param tag [Symbol, String] The rendered tag name
|
28
|
+
# @param src [String] The source url of the image.
|
29
|
+
# @param alt [String] Specifies an alternate text for the image.
|
30
|
+
# @param lazy [Boolean] Whether or not to lazily load the image.
|
31
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
32
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
33
|
+
def initialize(tag: DEFAULT_TAG, src:, alt:, lazy: false, classes: "", attributes: {})
|
34
|
+
@attributes = attributes
|
35
|
+
|
36
|
+
@src = src
|
37
|
+
@tag = check_incoming_tag(DEFAULT_TAG, tag)
|
38
|
+
@classes = classes
|
39
|
+
|
40
|
+
@attributes[:alt] = alt
|
41
|
+
@attributes[:src] = image_path(@src)
|
42
|
+
|
43
|
+
return unless lazy
|
44
|
+
|
45
|
+
@attributes[:loading] = :lazy
|
46
|
+
@attributes[:decoding] = :async
|
47
|
+
end
|
48
|
+
|
49
|
+
def call
|
50
|
+
render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# Represents two items side-by-side. Typically, this will be an icon (of CSS classes, SVG, or a Heroicon icon)
|
5
|
+
# with optional text.
|
6
|
+
#
|
7
|
+
# InlineFlexComponent differs from HeroiconComponent in that it is intended to be
|
8
|
+
# used within (or next to) text, whereas HeroiconComponent is intended to only
|
9
|
+
# present a static list of SVG images (and can be embedded in buttons or shown alone).
|
10
|
+
class InlineFlexComponent < Ariadne::Component
|
11
|
+
DEFAULT_TAG = :span
|
12
|
+
DEFAULT_CLASSES = "ariadne-inline-flex ariadne-items-baseline"
|
13
|
+
|
14
|
+
STATE_OPTIONS = [:closed, :open].freeze
|
15
|
+
|
16
|
+
STATE_OPEN_SVG = <<~MSG
|
17
|
+
<svg viewBox="0 0 24 24" width="12" height="12" class="ariadne-stroke-state-open" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
18
|
+
<circle cx="12" cy="12" r="10"></circle>
|
19
|
+
</svg>
|
20
|
+
MSG
|
21
|
+
STATE_CLOSED_SVG = <<~MSG
|
22
|
+
<svg viewBox="0 0 24 24" width="12" height="12" class="ariadne-stroke-state-closed fill-state-closed " stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
23
|
+
<circle cx="12" cy="12" r="10"></circle>
|
24
|
+
</svg>
|
25
|
+
MSG
|
26
|
+
|
27
|
+
DEFAULT_TEXT_OPEN_CLASSES = "ariadne-text-state-open"
|
28
|
+
DEFAULT_TEXT_CLOSED_CLASSES = "ariadne-text-state-closed"
|
29
|
+
DEFAULT_TEXT_CLASSES = "ariadne-pl-2 ariadne-text-sm ariadne-font-medium ariadne-text-gray-900"
|
30
|
+
renders_one :icon, lambda { |tag: :svg, icon:, variant:, size: Ariadne::HeroiconComponent::SIZE_DEFAULT, classes: "", attributes: {}, text_classes: "", text_attributes: {}|
|
31
|
+
actual_text_classes = class_names(DEFAULT_TEXT_CLASSES, text_classes)
|
32
|
+
Ariadne::HeroiconComponent.new(tag: tag, icon: icon, variant: variant, size: size, classes: classes, attributes: attributes, text_classes: actual_text_classes, text_attributes: text_attributes) { content }
|
33
|
+
}
|
34
|
+
|
35
|
+
renders_one :item, lambda { |classes: "", attributes: {}|
|
36
|
+
Ariadne::BaseComponent.new(tag: :span, classes: classes, attributes: attributes) { content }
|
37
|
+
}
|
38
|
+
|
39
|
+
DEFAULT_LABEL_CLASSES = "ariadne-pl-2 ariadne-text-sm ariadne-font-medium ariadne-text-gray-900"
|
40
|
+
renders_one :text, lambda { |classes: "", attributes: {}|
|
41
|
+
actual_classes = class_names(DEFAULT_LABEL_CLASSES, classes)
|
42
|
+
Ariadne::BaseComponent.new(tag: :span, classes: actual_classes, attributes: attributes) { content }
|
43
|
+
}
|
44
|
+
|
45
|
+
# @example Default
|
46
|
+
#
|
47
|
+
# <%= render(Ariadne::InlineFlexComponent.new) do |c| %>
|
48
|
+
# <% c.item { Ariadne::InlineFlexComponent::STATE_OPEN_SVG.html_safe } %>
|
49
|
+
# <% end %>
|
50
|
+
#
|
51
|
+
# <%= render(Ariadne::InlineFlexComponent.new) do |c| %>
|
52
|
+
# <% c.icon(icon: :check, size: :sm, variant: HeroiconsHelper::Icon::VARIANT_SOLID) %>
|
53
|
+
# <% c.text { "Closed" } %>
|
54
|
+
# <% end %>
|
55
|
+
#
|
56
|
+
# @param tag [Symbol, String] The rendered tag name
|
57
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
58
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
59
|
+
def initialize(tag: DEFAULT_TAG, classes: "", attributes: {})
|
60
|
+
@tag = check_incoming_tag(DEFAULT_TAG, tag)
|
61
|
+
@classes = class_names(DEFAULT_CLASSES, classes)
|
62
|
+
@attributes = attributes
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# Use `Link` for navigating from one page to another. `Link` styles anchor tags with default styling and hover text-decoration.
|
5
|
+
class LinkComponent < Ariadne::Component
|
6
|
+
DEFAULT_TAG = :a
|
7
|
+
TAG_OPTIONS = [DEFAULT_TAG, :span].freeze
|
8
|
+
|
9
|
+
DEFAULT_CLASSES = "ariadne-cursor-pointer"
|
10
|
+
DEFAULT_ACTIONABLE_CLASSES = " ariadne-cursor-pointer ariadne-underline ariadne-decoration-double ariadne-font-semibold hover:ariadne-text-button-text-color focus:ariadne-outline-none focus:ariadne-ring-2 focus:ariadne-ring-offset-2 focus:ariadne-ring-purple-500"
|
11
|
+
|
12
|
+
# `Tooltip` that appears on mouse hover or keyboard focus over the button. Use tooltips sparingly and as a last resort.
|
13
|
+
# **Important:** This tooltip defaults to `type: :description`. In a few scenarios, `type: :label` may be more appropriate.
|
14
|
+
# Consult the <%= link_to_component(Ariadne::TooltipComponent) %> documentation for more information.
|
15
|
+
#
|
16
|
+
# @param tag [Symbol, String] The rendered tag name
|
17
|
+
# @param text [String] The text content of the tooltip. This should be brief and no longer than a sentence.
|
18
|
+
# @param direction [Symbol] <%= one_of(Ariadne::TooltipComponent::VALID_PLACEMENTS) %>
|
19
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
20
|
+
# @param attributes [Hash] Same arguments as <%= link_to_component(Ariadne::TooltipComponent) %>.
|
21
|
+
renders_one :tooltip, lambda { |tag: Ariadne::TooltipComponent::DEFAULT_TAG, text:, direction: Ariadne::TooltipComponent::DEFAULT_PLACEMENT, type: Ariadne::TooltipComponent::TYPE_DEFAULT, classes: "", attributes: {}|
|
22
|
+
raise ArgumentError, "Links with a tooltip must have a unique `id` set on the `LinkComponent`." if @id.blank?
|
23
|
+
|
24
|
+
Ariadne::TooltipComponent.new(tag: tag, for_id: @id, text: text, direction: direction, type: type, classes: classes, attributes: attributes)
|
25
|
+
}
|
26
|
+
|
27
|
+
# @example Default
|
28
|
+
# <%= render(Ariadne::LinkComponent.new(href: "#")) { "Link" } %>
|
29
|
+
#
|
30
|
+
# @example Span as link
|
31
|
+
# <%= render(Ariadne::LinkComponent.new(tag: :span, href: "#")) { "Span as a link" } %>
|
32
|
+
#
|
33
|
+
# @example With tooltip
|
34
|
+
# @description
|
35
|
+
# Use tooltips sparingly and as a last resort. Consult the <%= link_to_component(Ariadne::TooltipComponent) %> documentation for more information.
|
36
|
+
# @code
|
37
|
+
# <%= render(Ariadne::LinkComponent.new(href: "#", attributes: { id: "link-with-tooltip" })) do |c| %>
|
38
|
+
# <% c.tooltip(text: "Tooltip text") %>
|
39
|
+
# Link
|
40
|
+
# <% end %>
|
41
|
+
#
|
42
|
+
# @param tag [String] <%= one_of(Ariadne::LinkComponent::TAG_OPTIONS) %>
|
43
|
+
# @param href [String] URL to be used for the link.
|
44
|
+
# @param actionable [Boolean] If true, adds additional classes to the link to make it more aware.
|
45
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
46
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
47
|
+
def initialize(tag: DEFAULT_TAG, href:, actionable: false, classes: "", attributes: {})
|
48
|
+
@tag = check_incoming_tag(DEFAULT_TAG, tag)
|
49
|
+
|
50
|
+
@attributes = attributes
|
51
|
+
@attributes[:href] = href
|
52
|
+
|
53
|
+
@id = @attributes[:id]
|
54
|
+
|
55
|
+
@classes = class_names(DEFAULT_CLASSES, classes)
|
56
|
+
@classes << DEFAULT_ACTIONABLE_CLASSES if actionable
|
57
|
+
end
|
58
|
+
|
59
|
+
def call
|
60
|
+
render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) do
|
61
|
+
content.to_s + tooltip.to_s
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
<%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |list| %>
|
2
|
+
<% items.each do |item| %>
|
3
|
+
<% if item.linked? %>
|
4
|
+
<%= render Ariadne::BaseComponent.new(tag: :li, classes: item.classes, attributes: item.attributes) do %>
|
5
|
+
<%= render Ariadne::LinkComponent.new(href: item.link[:href], classes: item.link[:classes], attributes: item.link[:attributes]) do %>
|
6
|
+
<%= item.entry %>
|
7
|
+
<% end %>
|
8
|
+
<% end %>
|
9
|
+
<% else %>
|
10
|
+
<%= render Ariadne::BaseComponent.new(tag: :li, classes: item.classes, attributes: item.attributes) do %>
|
11
|
+
<%= item.entry %>
|
12
|
+
<% end %>
|
13
|
+
<% end %>
|
14
|
+
<% end %>
|
15
|
+
<% end %>
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# `List` is used to show a list of items in a vertical format.
|
5
|
+
class ListComponent < Ariadne::Component
|
6
|
+
DEFAULT_TAG = :ul
|
7
|
+
DEFAULT_UL_CLASSES = "ariadne-divide-y ariadne-divide-gray-300"
|
8
|
+
|
9
|
+
renders_many :items, "ListItem"
|
10
|
+
|
11
|
+
# @example Basic
|
12
|
+
# <% numbers = [1, 2, 3] %>
|
13
|
+
# <%= render(Ariadne::ListComponent.new) do |list| %>
|
14
|
+
# <% numbers.each do |number| %>
|
15
|
+
# <%= list.item do |item| %>
|
16
|
+
# <%= item.entry { number } %>
|
17
|
+
# <% end %>
|
18
|
+
# <% end %>
|
19
|
+
# <% end %>
|
20
|
+
#
|
21
|
+
#
|
22
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
23
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
24
|
+
def initialize(classes: "", attributes: {})
|
25
|
+
@tag = DEFAULT_TAG
|
26
|
+
@classes = class_names(DEFAULT_UL_CLASSES, classes)
|
27
|
+
@attributes = attributes
|
28
|
+
end
|
29
|
+
|
30
|
+
def render?
|
31
|
+
items.any?
|
32
|
+
end
|
33
|
+
|
34
|
+
# This component is part of `ListComponent` and should not be
|
35
|
+
# used as a standalone component.
|
36
|
+
class ListItem < Ariadne::Component
|
37
|
+
DEFAULT_ITEM_CLASSES = "ariadne-relative ariadne-p-1.5 focus:ariadne-ring-2 focus:ariadne-ring-offset-2 focus:ariadne-ring-purple-500 hover:ariadne-bg-button-hover-color"
|
38
|
+
|
39
|
+
renders_one :entry, lambda { |static_content = nil, &block|
|
40
|
+
next static_content if static_content.present?
|
41
|
+
|
42
|
+
render(Ariadne::BaseComponent.new(tag: :div)) do
|
43
|
+
view_context.capture { block&.call }
|
44
|
+
end
|
45
|
+
}
|
46
|
+
|
47
|
+
attr_reader :link, :classes, :attributes
|
48
|
+
|
49
|
+
def initialize(link: {}, classes: "", attributes: {})
|
50
|
+
@link = link
|
51
|
+
@classes = class_names(DEFAULT_ITEM_CLASSES, classes)
|
52
|
+
@attributes = attributes
|
53
|
+
end
|
54
|
+
|
55
|
+
def selected?
|
56
|
+
@selected
|
57
|
+
end
|
58
|
+
|
59
|
+
def linked?
|
60
|
+
@link.present?
|
61
|
+
end
|
62
|
+
|
63
|
+
def call
|
64
|
+
Ariadne::BaseComponent.new(tag: :div, classes: @classes, attributes: @attributes)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# Add a general description of component here
|
5
|
+
# Add additional usage considerations or best practices that may aid the user to use the component correctly.
|
6
|
+
# @accessibility Add any accessibility considerations
|
7
|
+
class MainComponent < Ariadne::Component
|
8
|
+
DEFAULT_CLASSES = "flex-auto"
|
9
|
+
|
10
|
+
# @example Default
|
11
|
+
#
|
12
|
+
# <%= render(Ariadne::MainComponent.new) { "Example" } %>
|
13
|
+
#
|
14
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
15
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
16
|
+
def initialize(classes: "", attributes: {})
|
17
|
+
@tag = :main
|
18
|
+
@classes = class_names(
|
19
|
+
DEFAULT_CLASSES,
|
20
|
+
classes
|
21
|
+
)
|
22
|
+
|
23
|
+
@attributes = attributes
|
24
|
+
end
|
25
|
+
|
26
|
+
def call
|
27
|
+
render(Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes)) do
|
28
|
+
render(Ariadne::ContainerComponent.new) { content }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Ariadne
|
4
|
+
# Add a general description of component here
|
5
|
+
# Add additional usage considerations or best practices that may aid the user to use the component correctly.
|
6
|
+
# @accessibility Add any accessibility considerations
|
7
|
+
class NarrowContainerComponent < Ariadne::Component
|
8
|
+
DEFAULT_TAG = :div
|
9
|
+
TAG_OPTIONS = [DEFAULT_TAG].freeze
|
10
|
+
|
11
|
+
DEFAULT_CLASSES = "ariadne-max-w-7xl ariadne-mx-auto ariadne-py-12 ariadne-px-4 sm:ariadne-px-6 lg:ariadne-py-16 lg:ariadne-px-8"
|
12
|
+
|
13
|
+
# @example Default
|
14
|
+
# <%= render(Ariadne::NarrowContainerComponent.new) do |container| %>
|
15
|
+
# <%= render(Ariadne::ButtonComponent.new) { "Click me!" } %>
|
16
|
+
# <% end %>
|
17
|
+
#
|
18
|
+
# @param classes [String] <%= link_to_classes_docs %>
|
19
|
+
# @param attributes [Hash] <%= link_to_attributes_docs %>
|
20
|
+
def initialize(classes: "", attributes: {})
|
21
|
+
@tag = :div
|
22
|
+
@classes = class_names(
|
23
|
+
DEFAULT_CLASSES,
|
24
|
+
classes
|
25
|
+
)
|
26
|
+
|
27
|
+
@attributes = attributes
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%= render Ariadne::BaseComponent.new(tag: @tag, classes: @classes, attributes: @attributes) do |list| %>
|
2
|
+
<% panels.each_with_index do |panel, idx| %>
|
3
|
+
<%= render Ariadne::BaseComponent.new(tag: :li, classes: panel.classes, attributes: panel.attributes) do %>
|
4
|
+
<%= render Ariadne::BaseComponent.new(tag: :div, classes: Ariadne::PanelBarComponent::PanelItem::DEFAULT_WRAPPER_CLASSES) do %>
|
5
|
+
<span class="ariadne-px-6 ariadne-py-4 ariadne-flex ariadne-items-center ariadne-text-sm ariadne-font-medium">
|
6
|
+
<%= panel.icon %>
|
7
|
+
<span class="ariadne-ml-4 ariadne-text-sm ariadne-font-medium ariadne-text-gray-900"><%= panel.label %></span>
|
8
|
+
<!-- Arrow separator for lg screens and up -->
|
9
|
+
<% if idx + 1 < panels.size %>
|
10
|
+
<div class="md:ariadne-block ariadne-hidden ariadne-absolute ariadne-top-0 ariadne-right-0 ariadne-h-full ariadne-w-5" aria-hidden="true">
|
11
|
+
<svg class="ariadne-h-full ariadne-w-full ariadne-text-gray-300" viewBox="0 0 22 80" fill="none" preserveAspectRatio="none">
|
12
|
+
<path d="M0 -2L20 40L0 82" vector-effect="non-scaling-stroke" stroke="currentcolor" stroke-linejoin="round"></path>
|
13
|
+
</svg>
|
14
|
+
</div>
|
15
|
+
<% end %>
|
16
|
+
</span>
|
17
|
+
<% end %>
|
18
|
+
<% end %>
|
19
|
+
<% end %>
|
20
|
+
<% end %>
|