From 4e0e67e3743857d56a270373dbc818590fdbf6aa Mon Sep 17 00:00:00 2001 From: Seth Horsley Date: Tue, 4 Nov 2025 15:42:23 -0500 Subject: [PATCH 1/2] add blocks dynamic endpoint with iframe and update sidebar --- app/components/docs/visual_code_example.rb | 33 ++++++++++++++++++---- app/controllers/pages_controller.rb | 12 ++++++++ app/views/docs/button.rb | 8 ++---- app/views/docs/sidebar.rb | 20 +++++++++---- config/routes.rb | 5 ++-- 5 files changed, 60 insertions(+), 18 deletions(-) diff --git a/app/components/docs/visual_code_example.rb b/app/components/docs/visual_code_example.rb index c9347051..6cefb73e 100644 --- a/app/components/docs/visual_code_example.rb +++ b/app/components/docs/visual_code_example.rb @@ -13,14 +13,19 @@ def self.reset_collected_code @@collected_code = [] end - def initialize(title: nil, description: nil, src: nil, context: nil) + 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 @@ -55,7 +60,7 @@ def render_header def render_tab_triggers TabsList do render_tab_trigger("preview", "Preview", method(:eye_icon)) - render_tab_trigger("code", "Code", method(:code_icon)) + render_tab_trigger("code", "Code", method(:code_icon)) if @type == :component end end @@ -72,15 +77,25 @@ def render_tab_contents(&) end def render_preview_tab(&block) - return iframe_preview if @src + block_class_name = @content.to_s + + return iframe_preview(block_class_name) if @type == :block raw_preview end - def iframe_preview + 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 - iframe(src: @src, class: "size-full") + if @content + iframe(src: render_block_path(id: block_name, attributes: @content_attributes), class: "size-full") + else + iframe(srcdoc: safe("
You cannot render a ruby block for a block preview
"), 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 @@ -100,6 +115,14 @@ def render_code_tab 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", diff --git a/app/controllers/pages_controller.rb b/app/controllers/pages_controller.rb index 6ca7a4c0..b3870008 100644 --- a/app/controllers/pages_controller.rb +++ b/app/controllers/pages_controller.rb @@ -6,4 +6,16 @@ class PagesController < ApplicationController def home render Views::Pages::Home.new end + + def blocks + render Views::Pages::Blocks.new + end + + def render_block + self.class.layout -> { Views::Layouts::ExamplesLayout } + block_class_name = params[:id] + attributes = params[:attributes]&.permit!&.to_h&.symbolize_keys || {} + block_class = block_class_name.constantize + render block_class.new(**attributes) + end end diff --git a/app/views/docs/button.rb b/app/views/docs/button.rb index ee943b12..cc59bb42 100644 --- a/app/views/docs/button.rb +++ b/app/views/docs/button.rb @@ -45,11 +45,9 @@ def view_template RUBY end - render Docs::VisualCodeExample.new(title: "Link", context: self) do - <<~RUBY - Button(variant: :link) { "Link" } - RUBY - end + render Docs::VisualCodeExample.new(ruby_code: <<~RUBY, title: "Link", context: self) + Button(variant: :link) { "Link" } + RUBY render Docs::VisualCodeExample.new(title: "Disabled", context: self) do <<~RUBY diff --git a/app/views/docs/sidebar.rb b/app/views/docs/sidebar.rb index 165872fa..cc1e8638 100644 --- a/app/views/docs/sidebar.rb +++ b/app/views/docs/sidebar.rb @@ -29,13 +29,21 @@ def view_template end end - render Docs::VisualCodeExample.new(title: "Example", src: "/docs/sidebar/example", context: self) do - Views::Docs::Sidebar::Example::CODE - end + render Docs::VisualCodeExample.new( + title: "Example", + context: self, + type: :block, + content: Views::Docs::Sidebar::Example, + content_attributes: {sidebar_state: "open"} + ) - render Docs::VisualCodeExample.new(title: "Inset variant", src: "/docs/sidebar/inset", context: self) do - Views::Docs::Sidebar::InsetExample::CODE - end + render Docs::VisualCodeExample.new( + title: "Inset variant", + context: self, + type: :block, + content: Views::Docs::Sidebar::InsetExample, + content_attributes: {sidebar_state: "open"} + ) render Docs::VisualCodeExample.new(title: "Dialog variant", context: self) do <<~RUBY diff --git a/config/routes.rb b/config/routes.rb index a6da0ff2..73208daa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -51,8 +51,6 @@ get "sheet", to: "docs#sheet", as: :docs_sheet get "shortcut_key", to: "docs#shortcut_key", as: :docs_shortcut_key get "sidebar", to: "docs#sidebar", as: :docs_sidebar - get "sidebar/example", to: "docs/sidebar#example", as: :docs_sidebar_example - get "sidebar/inset", to: "docs/sidebar#inset_example", as: :docs_sidebar_inset get "skeleton", to: "docs#skeleton", as: :docs_skeleton get "switch", to: "docs#switch", as: :docs_switch get "table", to: "docs#table", as: :docs_table @@ -63,6 +61,9 @@ get "typography", to: "docs#typography", as: :docs_typography end + get "blocks", to: "pages#blocks", as: :blocks + get "blocks/:id", to: "pages#render_block", as: :render_block + match "/404", to: "errors#not_found", via: :all match "/500", to: "errors#internal_server_error", via: :all From 5b7af722fe31d4e0723c930be71771fdfbadea23 Mon Sep 17 00:00:00 2001 From: Seth Horsley Date: Mon, 9 Mar 2026 00:52:45 -0400 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8D=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/components/docs/visual_code_example.rb | 35 ++++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/app/components/docs/visual_code_example.rb b/app/components/docs/visual_code_example.rb index 9f8f2757..6cefb73e 100644 --- a/app/components/docs/visual_code_example.rb +++ b/app/components/docs/visual_code_example.rb @@ -13,14 +13,19 @@ def self.reset_collected_code @@collected_code = [] end - def initialize(title: nil, description: nil, src: nil, context: nil) + 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 @@ -55,7 +60,7 @@ def render_header def render_tab_triggers TabsList do render_tab_trigger("preview", "Preview", method(:eye_icon)) - render_tab_trigger("code", "Code", method(:code_icon)) + render_tab_trigger("code", "Code", method(:code_icon)) if @type == :component end end @@ -72,15 +77,25 @@ def render_tab_contents(&) end def render_preview_tab(&block) - return iframe_preview if @src + block_class_name = @content.to_s + + return iframe_preview(block_class_name) if @type == :block raw_preview end - def iframe_preview - div(class: "relative aspect-[4/2.5] w-full overflow-hidden rounded-md border", data: {controller: "iframe-theme"}) do + 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 - iframe(src: @src, class: "size-full", data: {iframe_theme_target: "iframe"}) + if @content + iframe(src: render_block_path(id: block_name, attributes: @content_attributes), class: "size-full") + else + iframe(srcdoc: safe("
You cannot render a ruby block for a block preview
"), 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 @@ -100,6 +115,14 @@ def render_code_tab 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",