-
Notifications
You must be signed in to change notification settings - Fork 28
Expand file tree
/
Copy pathvisual_code_example.rb
More file actions
167 lines (147 loc) · 5.23 KB
/
visual_code_example.rb
File metadata and controls
167 lines (147 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# frozen_string_literal: true
module Components
module Docs
class VisualCodeExample < Components::Base
@@collected_code = []
def self.collected_code
@@collected_code.join("\n")
end
def self.reset_collected_code
@@collected_code = []
end
def initialize(ruby_code: nil, title: nil, description: nil, src: nil, context: nil, type: :component, content: nil, content_attributes: nil)
@ruby_code = ruby_code
@title = title
@description = description
@src = src
@context = context
@type = type
@content = content
@content_attributes = content_attributes
end
def view_template(&)
# @display_code = @ruby_code || CGI.unescapeHTML(capture(&))
@display_code = CGI.unescapeHTML(capture(&))
@@collected_code << @display_code
div(id: @title) do
div(class: "relative") do
Tabs(default_value: "preview") do
div(class: "flex justify-between items-end mb-4 gap-x-2") do
render_header
div(class: "flex-grow") # Spacer
render_tab_triggers
end
render_tab_contents(&)
end
end
end
end
# standard:enable Style/ArgumentsForwarding
private
def render_header
div do
if @title
div do
Components.Heading(level: 4) { @title.capitalize }
end
end
p { @description } if @description
end
end
def render_tab_triggers
TabsList do
render_tab_trigger("preview", "Preview", method(:eye_icon))
render_tab_trigger("code", "Code", method(:code_icon)) if @type == :component
end
end
def render_tab_trigger(value, label, icon_method)
TabsTrigger(value: value) do
icon_method.call
span { label }
end
end
def render_tab_contents(&)
TabsContent(value: "preview") { render_preview_tab(&) }
TabsContent(value: "code") { render_code_tab }
end
def render_preview_tab(&block)
block_class_name = @content.to_s
return iframe_preview(block_class_name) if @type == :block
raw_preview
end
def iframe_preview(block_name)
div(class: "relative aspect-[4/2.5] w-full overflow-hidden rounded-md border") do
div(class: "absolute inset-0 hidden w-[1600px] bg-background md:block") do
if @content
iframe(src: render_block_path(id: block_name, attributes: @content_attributes), class: "size-full")
else
iframe(srcdoc: safe("<div>You cannot render a ruby block for a block preview</div>"), class: "size-full")
# TODO
# decoded_code = CGI.unescapeHTML(@display_code)
# html_content = render_block_to_html(decoded_code)
# iframe(srcdoc: safe(html_content), class: "size-full")
end
end
end
end
def raw_preview
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
div(class: "preview flex min-h-[350px] w-full justify-center p-10 items-center") do
decoded_code = CGI.unescapeHTML(@display_code)
@context.instance_eval(decoded_code)
end
end
end
def render_code_tab
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
Codeblock(@display_code, syntax: :ruby, class: "-m-px")
end
end
def render_block_to_html(code)
# Extract the component from "render ComponentName.new" pattern
# and evaluate it to generate standalone HTML
component_code = code.strip.sub(/^render\s+/, '')
component = eval(component_code)
component.call
end
def eye_icon
svg(
xmlns: "http://www.w3.org/2000/svg",
fill: "none",
viewbox: "0 0 24 24",
stroke_width: "1.5",
stroke: "currentColor",
class: "w-4 h-4 mr-2"
) do |s|
s.path(
stroke_linecap: "round",
stroke_linejoin: "round",
d:
"M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178z"
)
s.path(
stroke_linecap: "round",
stroke_linejoin: "round",
d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z"
)
end
end
def code_icon
svg(
xmlns: "http://www.w3.org/2000/svg",
fill: "none",
viewbox: "0 0 24 24",
stroke_width: "1.5",
stroke: "currentColor",
class: "w-4 h-4 mr-2"
) do |s|
s.path(
stroke_linecap: "round",
stroke_linejoin: "round",
d: "M17.25 6.75L22.5 12l-5.25 5.25m-10.5 0L1.5 12l5.25-5.25m7.5-3l-4.5 16.5"
)
end
end
end
end
end