Skip to content

Commit 651f708

Browse files
authored
Migrate the shared components to align with Phlex conversions (#167)
1 parent 6e173d0 commit 651f708

File tree

20 files changed

+587
-547
lines changed

20 files changed

+587
-547
lines changed

app/components/shared/container.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# frozen_string_literal: true
2+
3+
module Components
4+
module Shared
5+
class Container < Components::Base
6+
DEFAULT_CLASS = "container mx-auto w-full px-4"
7+
SIZE_CLASSES = {
8+
sm: "max-w-md",
9+
md: "max-w-2xl",
10+
lg: "max-w-4xl",
11+
xl: "max-w-6xl",
12+
"2xl": "max-w-7xl"
13+
}
14+
15+
def initialize(size: "md", **attrs)
16+
@attrs = attrs
17+
@attrs[:class] = [DEFAULT_CLASS, SIZE_CLASSES[size].to_s, @attrs[:class]]
18+
end
19+
20+
def view_template(&)
21+
div(**@attrs, &)
22+
end
23+
end
24+
end
25+
end

app/components/shared/flash.rb

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# frozen_string_literal: true
2+
3+
module Components
4+
module Shared
5+
class Flash < Components::Base
6+
# STYLE_CLASS = {
7+
# notice: 'bg-primary text-primary-foreground',
8+
# alert: 'bg-destructive text-destructive-foreground'
9+
# }
10+
# TRANSITION_CLASS = "transition ease-in-out data-[state=open]:animate-in data-[state=open]:fade-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500 inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom"
11+
12+
def initialize(variant: :notice, title: nil, description: nil)
13+
@variant = variant.to_sym
14+
@description = description
15+
@title = title
16+
end
17+
18+
def view_template(&block)
19+
li(
20+
role: "status",
21+
aria_live: "off",
22+
aria_atomic: "true",
23+
tabindex: "0",
24+
data_state: "open",
25+
data_controller: "dismissable",
26+
# data_swipe_direction: "right",
27+
class: [
28+
"group pointer-events-auto relative flex w-full items-center justify-between space-x-2 overflow-hidden rounded-md p-4 pr-6 pt-3.5 shadow-lg transition-all data-[state=open]:animate-in data-[state=closed]:animate-out data-[swipe=end]:animate-out data-[state=closed]:fade-out-80 data-[state=closed]:slide-out-to-right-full data-[state=open]:slide-in-from-top-full data-[state=open]:sm:slide-in-from-bottom-full border",
29+
("bg-background text-foreground" if notice?),
30+
("destructive group border-destructive bg-destructive text-destructive-foreground" if alert?)
31+
],
32+
style: "user-select:none; touch-action:none"
33+
) do
34+
div(class: "grid gap-1") do
35+
if @title
36+
div(class: "text-sm font-semibold [&+div]:text-xs") { @title }
37+
div(class: "text-sm opacity-90") { @description }
38+
else
39+
div { @description }
40+
end
41+
end
42+
block&.call
43+
close_button # sits at top right of toast
44+
end
45+
end
46+
47+
private
48+
49+
def close_button
50+
button(
51+
type: "button",
52+
class: [
53+
"absolute right-1 top-1 rounded-md p-1 opacity-0 transition-opacity focus:opacity-100 focus:outline-none focus:ring-1 focus:ring-ring group-hover:opacity-100",
54+
("text-foreground/50 hover:text-foreground" if notice?),
55+
("text-destructive-foreground/50 hover:text-destructive-foreground focus:ring-destructive-foreground focus:ring-offset-destructive-foreground" if alert?)
56+
],
57+
58+
data: {
59+
action: "click->dismissable#dismiss"
60+
}
61+
) do
62+
x_icon
63+
end
64+
end
65+
66+
def x_icon
67+
svg(
68+
width: "15",
69+
height: "15",
70+
viewbox: "0 0 15 15",
71+
fill: "none",
72+
xmlns: "http://www.w3.org/2000/svg",
73+
class: "h-4 w-4"
74+
) do |s|
75+
s.path(
76+
d:
77+
"M11.7816 4.03157C12.0062 3.80702 12.0062 3.44295 11.7816 3.2184C11.5571 2.99385 11.193 2.99385 10.9685 3.2184L7.50005 6.68682L4.03164 3.2184C3.80708 2.99385 3.44301 2.99385 3.21846 3.2184C2.99391 3.44295 2.99391 3.80702 3.21846 4.03157L6.68688 7.49999L3.21846 10.9684C2.99391 11.193 2.99391 11.557 3.21846 11.7816C3.44301 12.0061 3.80708 12.0061 4.03164 11.7816L7.50005 8.31316L10.9685 11.7816C11.193 12.0061 11.5571 12.0061 11.7816 11.7816C12.0062 11.557 12.0062 11.193 11.7816 10.9684L8.31322 7.49999L11.7816 4.03157Z",
78+
fill: "currentColor",
79+
fill_rule: "evenodd",
80+
clip_rule: "evenodd"
81+
)
82+
end
83+
end
84+
85+
def alert? = @variant == :alert
86+
87+
def notice? = @variant == :notice
88+
end
89+
end
90+
end

app/components/shared/flashes.rb

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# frozen_string_literal: true
2+
3+
module Components
4+
module Shared
5+
class Flashes < Components::Base
6+
def initialize(notice: nil, alert: nil)
7+
@notice = notice
8+
@alert = alert
9+
end
10+
11+
def view_template(&block)
12+
ol(
13+
tabindex: "-1",
14+
class:
15+
"pointer-events-none fixed top-0 z-[100] flex max-h-screen w-full flex-col-reverse p-4 sm:bottom-0 sm:right-0 sm:top-auto sm:flex-col md:max-w-[420px] gap-y-1"
16+
) do
17+
render Shared::Flash.new(variant: :notice, description: @notice) if @notice
18+
render Shared::Flash.new(variant: :alert, description: @alert) if @alert
19+
end
20+
end
21+
end
22+
end
23+
end

app/components/shared/grid_pattern.rb

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# frozen_string_literal: true
2+
3+
module Components
4+
module Shared
5+
class GridPattern < Components::Base
6+
def initialize(spacing: :md)
7+
sizes = {
8+
xs: 15,
9+
sm: 25,
10+
md: 50,
11+
lg: 100,
12+
xl: 200
13+
}
14+
15+
@spacing = sizes[spacing]
16+
end
17+
18+
def view_template
19+
svg(
20+
class:
21+
"absolute inset-0 -z-10 h-[calc(100vh_/_2)] w-full stroke-border [mask-image:radial-gradient(100%_100%_at_top_right,white,transparent)]",
22+
aria_hidden: "true"
23+
) do |s|
24+
s.defs do
25+
s.pattern(
26+
id: "0787a7c5-978c-4f66-83c7-11c213f99cb7",
27+
width: @spacing,
28+
height: @spacing,
29+
x: "50%",
30+
y: "-1",
31+
patternunits: "userSpaceOnUse"
32+
) { s.path(d: "M.5 200V.5H200", fill: "none") }
33+
end
34+
s.rect(
35+
width: "100%",
36+
height: "100%",
37+
stroke_width: "0",
38+
fill: "url(#0787a7c5-978c-4f66-83c7-11c213f99cb7)"
39+
)
40+
end
41+
end
42+
end
43+
end
44+
end

app/components/shared/head.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# frozen_string_literal: true
2+
3+
module Components
4+
module Shared
5+
class Head < Components::Base
6+
include Phlex::Rails::Layout
7+
8+
def view_template
9+
head do
10+
title { "RubyUI - Component Library" }
11+
meta name: "viewport", content: "width=device-width,initial-scale=1"
12+
meta name: "turbo-refresh-method", content: "morph"
13+
meta name: "turbo-refresh-scroll", content: "preserve"
14+
meta name: "view-transition", content: "same-origin"
15+
csp_meta_tag
16+
csrf_meta_tags
17+
stylesheet_link_tag "https://api.fontshare.com/v2/css?f[]=general-sans@1&display=swap", data_turbo_track: "reload"
18+
stylesheet_link_tag "application", data_turbo_track: "reload"
19+
javascript_include_tag "application", data_turbo_track: "reload", type: "module"
20+
end
21+
end
22+
end
23+
end
24+
end

app/components/shared/logo.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
3+
module Components
4+
module Shared
5+
class Logo < Components::Base
6+
def view_template
7+
a(href: root_url, class: "mr-6 flex items-center space-x-2") do
8+
Heading(level: 4, class: "flex items-center") {
9+
img(src: image_url("logo.svg"), class: "h-4 block dark:hidden")
10+
img(src: image_url("logo_dark.svg"), class: "h-4 hidden dark:block")
11+
span(class: "sr-only") { "RubyUI" }
12+
Badge(variant: :amber, size: :sm, class: "ml-2 whitespace-nowrap") { "Pre Release" }
13+
}
14+
end
15+
end
16+
end
17+
end
18+
end

app/components/shared/menu.rb

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# frozen_string_literal: true
2+
3+
module Components
4+
module Shared
5+
class Menu < Components::Base
6+
def view_template
7+
div(class: "pb-4") do
8+
# Main routes (Docs, Components, Themes, Github, Discord, Twitter)
9+
div(class: "md:hidden") do
10+
main_link("Docs", docs_introduction_path)
11+
main_link("Components", docs_accordion_path)
12+
main_link("Themes", theme_path("default"))
13+
main_link("Github", "https://github.com/PhlexUI/phlex_ui")
14+
main_link("Discord", ENV["DISCORD_INVITE_LINK"])
15+
main_link("Twitter", ENV["PHLEXUI_TWITTER_LINK"])
16+
end
17+
18+
# GETTING STARTED
19+
h4(class: "mb-1 mt-4 rounded-md px-2 py-1 text-sm font-semibold") { "Getting Started" }
20+
div(class: "grid grid-flow-row auto-rows-max text-sm") do
21+
getting_started_links.each do |getting_started|
22+
menu_link(getting_started)
23+
end
24+
end
25+
26+
# INSTALLATION
27+
h4(class: "mb-1 mt-4 rounded-md px-2 py-1 text-sm font-semibold") { "Installation" }
28+
div(class: "grid grid-flow-row auto-rows-max text-sm") do
29+
installation_links.each do |installation|
30+
menu_link(installation)
31+
end
32+
end
33+
34+
# COMPONENTS
35+
h4(class: "mb-1 mt-4 rounded-md px-2 py-1 text-sm font-semibold flex items-center gap-x-2") do
36+
plain "Components"
37+
Badge(variant: :primary, size: :sm) { components.count.to_s }
38+
end
39+
div(class: "grid grid-flow-row auto-rows-max text-sm") do
40+
components.each do |component|
41+
menu_link(component)
42+
end
43+
end
44+
end
45+
end
46+
47+
def getting_started_links
48+
[
49+
{name: "Introduction", path: docs_introduction_path},
50+
{name: "Installation", path: docs_installation_path},
51+
{name: "Dark mode", path: docs_dark_mode_path},
52+
{name: "Theming", path: docs_theming_path},
53+
{name: "Customizing components", path: docs_customizing_components_path}
54+
]
55+
end
56+
57+
def installation_links
58+
[
59+
{name: "Rails - JS Bundler", path: docs_installation_rails_bundler_path},
60+
{name: "Rails - Importmaps", path: docs_installation_rails_importmaps_path}
61+
]
62+
end
63+
64+
def components
65+
[
66+
{name: "Accordion", path: docs_accordion_path},
67+
{name: "Alert", path: docs_alert_path},
68+
{name: "Alert Dialog", path: docs_alert_dialog_path},
69+
{name: "Aspect Ratio", path: docs_aspect_ratio_path},
70+
{name: "Avatar", path: docs_avatar_path},
71+
{name: "Badge", path: docs_badge_path},
72+
{name: "Breadcrumb", path: docs_breadcrumb_path, badge: "New"},
73+
{name: "Button", path: docs_button_path},
74+
{name: "Calendar", path: docs_calendar_path},
75+
{name: "Card", path: docs_card_path},
76+
# { name: "Chart", path: docs_chart_path, badge: "New" },
77+
{name: "Checkbox", path: docs_checkbox_path},
78+
{name: "Checkbox Group", path: docs_checkbox_group_path},
79+
{name: "Clipboard", path: docs_clipboard_path},
80+
{name: "Codeblock", path: docs_codeblock_path},
81+
{name: "Collapsible", path: docs_collapsible_path},
82+
{name: "Combobox", path: docs_combobox_path, badge: "Updated"},
83+
{name: "Command", path: docs_command_path},
84+
{name: "Context Menu", path: docs_context_menu_path},
85+
{name: "Date Picker", path: docs_date_picker_path},
86+
{name: "Dialog / Modal", path: docs_dialog_path},
87+
{name: "Dropdown Menu", path: docs_dropdown_menu_path},
88+
{name: "Form", path: docs_form_path},
89+
{name: "Hover Card", path: docs_hover_card_path},
90+
{name: "Input", path: docs_input_path},
91+
{name: "Link", path: docs_link_path},
92+
{name: "Masked Input", path: masked_input_path},
93+
{name: "Pagination", path: docs_pagination_path, badge: "New"},
94+
{name: "Popover", path: docs_popover_path},
95+
{name: "Progress", path: docs_progress_path, badge: "New"},
96+
{name: "Radio Button", path: docs_radio_button_path, badge: "New"},
97+
{name: "Select", path: docs_select_path, badge: "New"},
98+
{name: "Sheet", path: docs_sheet_path},
99+
{name: "Shortcut Key", path: docs_shortcut_key_path},
100+
{name: "Skeleton", path: docs_skeleton_path, badge: "New"},
101+
{name: "Switch", path: docs_switch_path},
102+
{name: "Table", path: docs_table_path},
103+
{name: "Tabs", path: docs_tabs_path},
104+
{name: "Textarea", path: docs_textarea_path},
105+
{name: "Theme Toggle", path: docs_theme_toggle_path},
106+
{name: "Tooltip", path: docs_tooltip_path},
107+
{name: "Typography", path: docs_typography_path}
108+
]
109+
end
110+
111+
def menu_link(component)
112+
current_path = component[:path] == request.path
113+
a(
114+
href: component[:path],
115+
class: [
116+
"group flex w-full items-center rounded-md border border-transparent px-2 py-1 hover:underline",
117+
(current_path ? "text-foreground font-medium" : "text-muted-foreground")
118+
]
119+
) do
120+
span(class: "flex items-center gap-x-1") do
121+
span { component[:name] }
122+
Badge(variant: :success, size: :sm, class: "ml-1") { component[:badge] } if component[:badge]
123+
end
124+
end
125+
end
126+
127+
def main_link(name, path)
128+
current_path = path == request.path
129+
a(
130+
href: path,
131+
class: [
132+
"group flex w-full items-center rounded-md border border-transparent px-2 py-1 hover:underline",
133+
(current_path ? "text-foreground font-medium" : "text-muted-foreground")
134+
]
135+
) do
136+
name
137+
end
138+
end
139+
end
140+
end
141+
end

0 commit comments

Comments
 (0)