Skip to content

Commit 6d50c4a

Browse files
lsouoliveirasethhorsley
authored andcommitted
Add sidebar component (#186)
Co-authored-by: Seth Horsley <github.dvxhi@sl.isethi.com>
1 parent 80bb99d commit 6d50c4a

9 files changed

Lines changed: 812 additions & 2 deletions

File tree

app/components/docs/visual_code_example.rb

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,10 @@ def self.reset_collected_code
1313
@@collected_code = []
1414
end
1515

16-
def initialize(title: nil, description: nil, context: nil)
16+
def initialize(title: nil, description: nil, src: nil, context: nil)
1717
@title = title
1818
@description = description
19+
@src = src
1920
@context = context
2021
end
2122

@@ -43,7 +44,7 @@ def view_template(&)
4344
def render_header
4445
div do
4546
if @title
46-
div(class: "flex items-center gap-x-2 mb-1") do
47+
div do
4748
Components.Heading(level: 4) { @title.capitalize }
4849
end
4950
end
@@ -71,6 +72,20 @@ def render_tab_contents(&)
7172
end
7273

7374
def render_preview_tab(&block)
75+
return iframe_preview if @src
76+
77+
raw_preview
78+
end
79+
80+
def iframe_preview
81+
div(class: "relative aspect-[4/2.5] w-full overflow-hidden rounded-md border") do
82+
div(class: "absolute inset-0 hidden w-[1600px] bg-background md:block") do
83+
iframe(src: @src, class: "size-full")
84+
end
85+
end
86+
end
87+
88+
def raw_preview
7489
div(class: "mt-2 ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 relative rounded-md border") do
7590
div(class: "preview flex min-h-[350px] w-full justify-center p-10 items-center") do
7691
decoded_code = CGI.unescapeHTML(@display_code)

app/components/shared/menu.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ def components
9999
{name: "Separator", path: docs_separator_path, badge: "New"},
100100
{name: "Sheet", path: docs_sheet_path},
101101
{name: "Shortcut Key", path: docs_shortcut_key_path},
102+
{name: "Sidebar", path: docs_sidebar_path, badge: "New"},
102103
{name: "Skeleton", path: docs_skeleton_path, badge: "New"},
103104
{name: "Switch", path: docs_switch_path},
104105
{name: "Table", path: docs_table_path},
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# frozen_string_literal: true
2+
3+
class Docs::SidebarController < ApplicationController
4+
layout -> { Views::Layouts::ExamplesLayout }
5+
6+
def example
7+
sidebar_state = cookies.fetch(:sidebar_state, "true") == "true"
8+
9+
render Views::Docs::Sidebar::Example.new(sidebar_state:)
10+
end
11+
12+
def inset_example
13+
sidebar_state = cookies.fetch(:sidebar_state, "true") == "true"
14+
15+
render Views::Docs::Sidebar::InsetExample.new(sidebar_state:)
16+
end
17+
end

app/controllers/docs_controller.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ def shortcut_key
178178
render Views::Docs::ShortcutKey.new
179179
end
180180

181+
def sidebar
182+
render Views::Docs::Sidebar.new
183+
end
184+
181185
def skeleton
182186
render Views::Docs::Skeleton.new
183187
end

app/views/docs/sidebar.rb

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
# frozen_string_literal: true
2+
3+
class Views::Docs::Sidebar < Views::Base
4+
def view_template
5+
component = "Sidebar"
6+
7+
div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do
8+
render Docs::Header.new(title: "Sidebar", description: "A composable, themeable and customizable sidebar component.")
9+
10+
Heading(level: 2) { "Usage" }
11+
12+
Alert do
13+
info_icon
14+
AlertTitle { "Requirements" }
15+
AlertDescription { "The sidebar component depends on the following components:" }
16+
ul(class: "list-disc list-inside") do
17+
li do
18+
InlineLink(href: docs_sheet_path, target: "_blank", class: "inline-flex items-center gap-2") do
19+
span { "Sheet" }
20+
external_icon_link
21+
end
22+
end
23+
li do
24+
div(class: "inline-flex items-center gap-2") do
25+
InlineLink(href: docs_separator_path, target: "_blank") { "Separator" }
26+
external_icon_link
27+
end
28+
end
29+
end
30+
end
31+
32+
render Docs::VisualCodeExample.new(title: "Example", src: "/docs/sidebar/example", context: self) do
33+
Views::Docs::Sidebar::Example::CODE
34+
end
35+
36+
render Docs::VisualCodeExample.new(title: "Inset variant", src: "/docs/sidebar/inset", context: self) do
37+
Views::Docs::Sidebar::InsetExample::CODE
38+
end
39+
40+
render Docs::VisualCodeExample.new(title: "Dialog variant", context: self) do
41+
<<~RUBY
42+
Dialog(data: {action: "ruby-ui--dialog:connect->ruby-ui--dialog#open"}) do
43+
DialogTrigger do
44+
Button { "Open Dialog" }
45+
end
46+
DialogContent(class: "grid overflow-hidden p-0 md:max-h-[500px] md:max-w-[700px] lg:max-w-[800px]") do
47+
SidebarWrapper(class: "items-start") do
48+
Sidebar(collapsible: :none, class: "hidden md:flex") do
49+
SidebarContent do
50+
SidebarGroup do
51+
SidebarGroupContent do
52+
SidebarMenu do
53+
SidebarMenuItem do
54+
SidebarMenuButton(as: :a, href: "#") do
55+
search_icon()
56+
span { "Search" }
57+
end
58+
end
59+
SidebarMenuItem do
60+
SidebarMenuButton(as: :a, href: "#", active: true) do
61+
home_icon()
62+
span { "Home" }
63+
end
64+
end
65+
SidebarMenuItem do
66+
SidebarMenuButton(as: :a, href: "#") do
67+
inbox_icon()
68+
span { "Inbox" }
69+
end
70+
end
71+
end
72+
end
73+
end
74+
end
75+
end
76+
main(class: "flex h-[480px] flex-1 flex-col overflow-hidden") do
77+
end
78+
end
79+
end
80+
end
81+
RUBY
82+
end
83+
84+
render Components::ComponentSetup::Tabs.new(component_name: component)
85+
86+
render Docs::ComponentsTable.new(component_files(component))
87+
end
88+
end
89+
90+
def search_icon
91+
svg(
92+
xmlns: "http://www.w3.org/2000/svg",
93+
width: "24",
94+
height: "24",
95+
viewBox: "0 0 24 24",
96+
fill: "none",
97+
stroke: "currentColor",
98+
stroke_width: "2",
99+
stroke_linecap: "round",
100+
stroke_linejoin: "round",
101+
class: "lucide lucide-search"
102+
) do |s|
103+
s.circle(cx: "11", cy: "11", r: "8")
104+
s.path(d: "M21 21L16.7 16.7")
105+
end
106+
end
107+
108+
def home_icon
109+
svg(
110+
xmlns: "http://www.w3.org/2000/svg",
111+
width: "24",
112+
height: "24",
113+
viewBox: "0 0 24 24",
114+
fill: "none",
115+
stroke: "currentColor",
116+
stroke_width: "2",
117+
stroke_linecap: "round",
118+
stroke_linejoin: "round",
119+
class: "lucide lucide-house"
120+
) do |s|
121+
s.path(d: "M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8")
122+
s.path(d: "M3 10a2 2 0 0 1 .709-1.528l7-5.999a2 2 0 0 1 2.582 0l7 5.999A2 2 0 0 1 21 10v9a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z")
123+
end
124+
end
125+
126+
def inbox_icon
127+
svg(
128+
xmlns: "http://www.w3.org/2000/svg",
129+
width: "24",
130+
height: "24",
131+
viewBox: "0 0 24 24",
132+
fill: "none",
133+
stroke: "currentColor",
134+
stroke_width: "2",
135+
stroke_linecap: "round",
136+
stroke_linejoin: "round",
137+
class: "lucide lucide-inbox"
138+
) do |s|
139+
s.polyline(points: "22 12 16 12 14 15 10 15 8 12 2 12")
140+
s.path(d: "M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z")
141+
end
142+
end
143+
144+
def external_icon_link
145+
svg(
146+
xmlns: "http://www.w3.org/2000/svg",
147+
viewBox: "0 0 24 24",
148+
fill: "none",
149+
stroke: "currentColor",
150+
stroke_width: "2",
151+
stroke_linecap: "round",
152+
stroke_linejoin: "round",
153+
class: "lucide lucide-external-link-icon lucide-external-link size-3"
154+
) do |s|
155+
s.path(d: "M15 3h6v6")
156+
s.path(d: "M10 14 21 3")
157+
s.path(d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6")
158+
end
159+
end
160+
161+
def info_icon
162+
svg(
163+
xmlns: "http://www.w3.org/2000/svg",
164+
viewbox: "0 0 24 24",
165+
fill: "currentColor",
166+
class: "w-5 h-5"
167+
) do |s|
168+
s.path(
169+
fill_rule: "evenodd",
170+
d:
171+
"M2.25 12c0-5.385 4.365-9.75 9.75-9.75s9.75 4.365 9.75 9.75-4.365 9.75-9.75 9.75S2.25 17.385 2.25 12zm8.706-1.442c1.146-.573 2.437.463 2.126 1.706l-.709 2.836.042-.02a.75.75 0 01.67 1.34l-.04.022c-1.147.573-2.438-.463-2.127-1.706l.71-2.836-.042.02a.75.75 0 11-.671-1.34l.041-.022zM12 9a.75.75 0 100-1.5.75.75 0 000 1.5z",
172+
clip_rule: "evenodd"
173+
)
174+
end
175+
end
176+
end

0 commit comments

Comments
 (0)