diff --git a/lib/ruby_ui/docs/base.rb b/lib/ruby_ui/docs/base.rb index b3acbff9..459cf6a3 100644 --- a/lib/ruby_ui/docs/base.rb +++ b/lib/ruby_ui/docs/base.rb @@ -10,5 +10,81 @@ def Heading(level:, &) def component_files(component_name) [] end + + # Text helper for wrapping paragraphs + def Text(&) + p(&) + end + + # InlineLink helper for documentation links + def InlineLink(href:, target: nil, class: nil, &) + a(href: href, target: target, class: binding.local_variable_get(:class), &) + end + + # Alert component helpers + def Alert(&) + div(&) + end + + def AlertTitle(&) + h4(&) + end + + def AlertDescription(&) + p(&) + end + + # Route helper stubs - return "#" as placeholder + def docs_sheet_path + "#" + end + + def docs_separator_path + "#" + end + + def docs_accordion_path + "#" + end + + def docs_alert_path + "#" + end + + def docs_alert_dialog_path + "#" + end + + def docs_aspect_ratio_path + "#" + end + + def docs_avatar_path + "#" + end + + def docs_badge_path + "#" + end + + def docs_installation_path + "#" + end + + # InlineCode helper for typography examples + def InlineCode(&) + code(&) + end + end +end + +# Module-level components stub +module Components + def self.Heading(level:, &block) + # Stub for module-level Heading calls + end + + def self.TypographyList(items:, numbered: false) + # Stub for TypographyList component end end diff --git a/lib/ruby_ui/docs/sidebar_examples.rb b/lib/ruby_ui/docs/sidebar_examples.rb new file mode 100644 index 00000000..e9db4a34 --- /dev/null +++ b/lib/ruby_ui/docs/sidebar_examples.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +# Stub constants for sidebar documentation examples +# These are replaced with actual implementations in the web app + +module Views + module Docs + class Sidebar < Views::Base + class Example + CODE = <<~RUBY + # Sidebar example code placeholder + RUBY + end + + class InsetExample + CODE = <<~RUBY + # Sidebar inset example code placeholder + RUBY + end + end + end +end diff --git a/lib/ruby_ui/docs/visual_code_example.rb b/lib/ruby_ui/docs/visual_code_example.rb index 0007c3f3..39c6154d 100644 --- a/lib/ruby_ui/docs/visual_code_example.rb +++ b/lib/ruby_ui/docs/visual_code_example.rb @@ -2,15 +2,18 @@ module Docs class VisualCodeExample < Phlex::HTML - def initialize(title:, context:) + def initialize(title:, context:, description: nil, src: nil) @title = title @context = context + @description = description + @src = src end def view_template(&block) code = block.call div do h3 { @title } + p { @description } if @description pre { code } @context.instance_eval(code) end diff --git a/lib/ruby_ui/popover/popover_docs.rb b/lib/ruby_ui/popover/popover_docs.rb new file mode 100644 index 00000000..1046dc25 --- /dev/null +++ b/lib/ruby_ui/popover/popover_docs.rb @@ -0,0 +1,971 @@ +# frozen_string_literal: true + +class Views::Docs::Popover < Views::Base + def view_template + component = "Popover" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Popover", description: "Displays rich content in a portal, triggered by a button.") + + render Docs::VisualCodeExample.new(title: "Example", context: self) do + <<~RUBY + Popover do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline) { "Open Popover" } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Placement", context: self) do + <<~RUBY + div(class: 'grid grid-cols-1 sm:grid-cols-3 gap-4') do + # -- TOP -- + Popover(options: { placement: 'top' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'top' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + Popover(options: { placement: 'top-start' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'top-start' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + Popover(options: { placement: 'top-end' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'top-end' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + # -- RIGHT -- + Popover(options: { placement: 'right' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'right' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + Popover(options: { placement: 'right-start' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'right-start' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + Popover(options: { placement: 'right-end' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'right-end' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + # -- LEFT -- + Popover(options: { placement: 'left' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'left' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + Popover(options: { placement: 'left-start' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'left-start' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + Popover(options: { placement: 'left-end' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'left-end' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + # -- BOTTOM -- + Popover(options: { placement: 'bottom' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'bottom' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + Popover(options: { placement: 'bottom-start' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'bottom-start' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + + Popover(options: { placement: 'bottom-end' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline, class: 'w-full justify-center') { 'bottom-end' } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Trigger", context: self) do + <<~RUBY + Popover(options: { trigger: 'click' }) do + PopoverTrigger(class: 'w-full') do + Button(variant: :outline) { "Click" } + end + PopoverContent(class: 'w-40') do + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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.982 18.725A7.488 7.488 0 0012 15.75a7.488 7.488 0 00-5.982 2.975m11.963 0a9 9 0 10-11.963 0m11.963 0A8.966 8.966 0 0112 21a8.966 8.966 0 01-5.982-2.275M15 9.75a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Profile" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M10.343 3.94c.09-.542.56-.94 1.11-.94h1.093c.55 0 1.02.398 1.11.94l.149.894c.07.424.384.764.78.93.398.164.855.142 1.205-.108l.737-.527a1.125 1.125 0 011.45.12l.773.774c.39.389.44 1.002.12 1.45l-.527.737c-.25.35-.272.806-.107 1.204.165.397.505.71.93.78l.893.15c.543.09.94.56.94 1.109v1.094c0 .55-.397 1.02-.94 1.11l-.893.149c-.425.07-.765.383-.93.78-.165.398-.143.854.107 1.204l.527.738c.32.447.269 1.06-.12 1.45l-.774.773a1.125 1.125 0 01-1.449.12l-.738-.527c-.35-.25-.806-.272-1.203-.107-.397.165-.71.505-.781.929l-.149.894c-.09.542-.56.94-1.11.94h-1.094c-.55 0-1.019-.398-1.11-.94l-.148-.894c-.071-.424-.384-.764-.781-.93-.398-.164-.854-.142-1.204.108l-.738.527c-.447.32-1.06.269-1.45-.12l-.773-.774a1.125 1.125 0 01-.12-1.45l.527-.737c.25-.35.273-.806.108-1.204-.165-.397-.505-.71-.93-.78l-.894-.15c-.542-.09-.94-.56-.94-1.109v-1.094c0-.55.398-1.02.94-1.11l.894-.149c.424-.07.765-.383.93-.78.165-.398.143-.854-.107-1.204l-.527-.738a1.125 1.125 0 01.12-1.45l.773-.773a1.125 1.125 0 011.45-.12l.737.527c.35.25.807.272 1.204.107.397-.165.71-.505.78-.929l.15-.894z" + ) + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: "M15 12a3 3 0 11-6 0 3 3 0 016 0z" + ) + end + plain "Settings" + end + Link(href: "#", variant: :ghost, class: 'w-full justify-start pl-2') do + 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: + "M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" + ) + end + plain "Logout" + end + end + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end diff --git a/lib/ruby_ui/progress/progress_docs.rb b/lib/ruby_ui/progress/progress_docs.rb new file mode 100644 index 00000000..dc2a7c47 --- /dev/null +++ b/lib/ruby_ui/progress/progress_docs.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class Views::Docs::Progress < Views::Base + def view_template + component = "Progress" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Progress", description: "Displays an indicator showing the completion progress of a task, typically displayed as a progress bar.") + + render Docs::VisualCodeExample.new(title: "Example", context: self) do + <<~RUBY + Progress(value: 50, class: "w-[60%]") + RUBY + end + + render Docs::VisualCodeExample.new(title: "With custom indicator color", context: self) do + <<~RUBY + Progress(value: 35, class: "w-[60%] [&>*]:bg-success") + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end diff --git a/lib/ruby_ui/radio_button/radio_button_docs.rb b/lib/ruby_ui/radio_button/radio_button_docs.rb new file mode 100644 index 00000000..15d0e024 --- /dev/null +++ b/lib/ruby_ui/radio_button/radio_button_docs.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +class Views::Docs::RadioButton < Views::Base + def view_template + component = "RadioButton" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Radio Button", description: "A control that allows users to make a single selection from a list of options.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Example", context: self) do + <<~RUBY + div(class: "flex items-center space-x-2") do + RadioButton(id: "default") + FormFieldLabel(for: "default") { "Default" } + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Checked", context: self) do + <<~RUBY + div(class: "flex items-center space-x-2") do + RadioButton(id: "checked", checked: true) + FormFieldLabel(for: "checked") { "Checked" } + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Disabled", context: self) do + <<~RUBY + div(class: "flex flex-row items-center gap-2") do + RadioButton(class: "peer",id: "disabled", disabled: true) + FormFieldLabel(for: "disabled") { "Disabled" } + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Aria Disabled", context: self) do + <<~RUBY + div(class: "flex flex-row items-center gap-2") do + RadioButton(class: "peer", id: "aria-disabled", aria: {disabled: "true"}) + FormFieldLabel(for: "aria-disabled") { "Aria Disabled" } + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end diff --git a/lib/ruby_ui/select/select_docs.rb b/lib/ruby_ui/select/select_docs.rb new file mode 100644 index 00000000..0209b22f --- /dev/null +++ b/lib/ruby_ui/select/select_docs.rb @@ -0,0 +1,129 @@ +# frozen_string_literal: true + +class Views::Docs::Select < Views::Base + def view_template + component = "Select" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Select", description: "Displays a list of options for the user to pick from—triggered by a button.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Select (Deconstructed)", context: self) do + <<~RUBY + Select(class: "w-56") do + SelectInput(value: "apple", id: "select-a-fruit") + + SelectTrigger do + SelectValue(placeholder: "Select a fruit", id: "select-a-fruit") { "Apple" } + end + + SelectContent(outlet_id: "select-a-fruit") do + SelectGroup do + SelectLabel { "Fruits" } + SelectItem(value: "apple") { "Apple" } + SelectItem(value: "orange") { "Orange" } + SelectItem(value: "banana") { "Banana" } + SelectItem(value: "watermelon") { "Watermelon" } + end + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Pre-selected Item", context: self) do + <<~RUBY + Select(class: "w-56") do + SelectInput(value: "banana", id: "select-preselected-fruit") + + SelectTrigger do + SelectValue(placeholder: "Select a fruit", id: "select-preselected-fruit") { "Banana" } + end + + SelectContent(outlet_id: "select-preselected-fruit") do + SelectGroup do + SelectLabel { "Fruits" } + SelectItem(value: "apple") { "Apple" } + SelectItem(value: "orange") { "Orange" } + SelectItem(value: "banana") { "Banana" } + SelectItem(value: "watermelon") { "Watermelon" } + end + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Disabled", context: self) do + <<~RUBY + Select(class: "w-56") do + SelectInput(value: "apple", id: "select-a-fruit") + + SelectTrigger(disabled: true) do + SelectValue(placeholder: "Select a fruit", id: "select-a-fruit") { "Apple" } + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Data Disabled", context: self) do + <<~RUBY + Select(class: "w-56") do + SelectInput(value: "apple", id: "select-a-fruit") + + SelectTrigger do + SelectValue(placeholder: "Select a fruit", id: "select-a-fruit") { "Apple" } + end + + SelectContent(outlet_id: "select-a-fruit") do + SelectGroup do + SelectLabel { "Fruits" } + SelectItem(data: {disabled: true}, value: "apple") { "Apple" } + SelectItem(value: "orange") { "Orange" } + SelectItem(value: "banana") { "Banana" } + SelectItem(data: {disabled: true}, value: "watermelon") { "Watermelon" } + end + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Aria Disabled Trigger", context: self) do + <<~RUBY + Select(class: "w-56") do + SelectInput(value: "apple", id: "select-a-fruit") + + SelectTrigger(aria: {disabled: "true"}) do + SelectValue(placeholder: "Select a fruit", id: "select-a-fruit") { "Apple" } + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Aria Disabled Item", context: self) do + <<~RUBY + Select(class: "w-56") do + SelectInput(value: "apple", id: "select-a-fruit") + + SelectTrigger do + SelectValue(placeholder: "Select a fruit", id: "select-a-fruit") { "Apple" } + end + + SelectContent(outlet_id: "select-a-fruit") do + SelectGroup do + SelectLabel { "Fruits" } + SelectItem(aria: {disabled: "true"}, value: "apple") { "Apple" } + SelectItem(value: "orange") { "Orange" } + SelectItem(value: "banana") { "Banana" } + SelectItem(aria: {disabled: "true"}, value: "watermelon") { "Watermelon" } + end + end + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end diff --git a/lib/ruby_ui/separator/separator_docs.rb b/lib/ruby_ui/separator/separator_docs.rb new file mode 100644 index 00000000..c5d980d6 --- /dev/null +++ b/lib/ruby_ui/separator/separator_docs.rb @@ -0,0 +1,36 @@ +# frozen_string_literal: true + +class Views::Docs::Separator < Views::Base + def view_template + component = "Separator" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Separator", description: "Visually or semantically separates content.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Example", context: self) do + <<~RUBY + div do + div(class: "space-y-1") do + h4(class: "text-sm font-medium leading-none") { "RubyUI" } + p(class: "text-sm text-muted-foreground") { "An open-source UI component library." } + end + Separator(class: "my-4") + div(class: "flex h-5 items-center space-x-4 text-sm") do + div { "Blog" } + Separator(as: :hr, orientation: :vertical) + div { "Docs" } + Separator(orientation: :vertical) + div { "Source" } + end + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end diff --git a/lib/ruby_ui/sheet/sheet_docs.rb b/lib/ruby_ui/sheet/sheet_docs.rb new file mode 100644 index 00000000..8865c0a2 --- /dev/null +++ b/lib/ruby_ui/sheet/sheet_docs.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +class Views::Docs::Sheet < Views::Base + def view_template + component = "Sheet" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Sheet", description: "Extends the Sheet component to display content that complements the main content of the screen.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Example", context: self) do + <<~RUBY + Sheet do + SheetTrigger do + Button(variant: :outline) { "Open Sheet" } + end + SheetContent(class: 'sm:max-w-sm') do + SheetHeader do + SheetTitle { "Edit profile" } + SheetDescription { "Make changes to your profile here. Click save when you're done." } + end + + SheetMiddle do + label { "Name" } + Input(placeholder: "Joel Drapper") { "Joel Drapper" } + label { "Email" } + Input(placeholder: "joel@drapper.me") + end + SheetFooter do + Button(variant: :outline, data: { action: 'click->ruby-ui--sheet-content#close' }) { "Cancel" } + Button(type: "submit") { "Save" } + end + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Side", description: "Use the side property to indicate the edge of the screen where the component will appear.", context: self) do + <<~RUBY + div(class: 'grid grid-cols-2 gap-4') do + # -- TOP -- + Sheet do + SheetTrigger do + Button(variant: :outline, class: 'w-full justify-center') { :top } + end + SheetContent(side: :top, class: ("sm:max-w-sm" if [:left, :right].include?(:top))) do + SheetHeader do + SheetTitle { "Edit profile" } + SheetDescription { "Make changes to your profile here. Click save when you're done." } + end + Form do + SheetMiddle do + label { "Name" } + Input(placeholder: "Joel Drapper") { "Joel Drapper" } + + label { "Email" } + Input(placeholder: "joel@drapper.me") + end + SheetFooter do + Button(variant: :outline, data: { action: 'click->ruby-ui--sheet-content#close' }) { "Cancel" } + Button(type: "submit") { "Save" } + end + end + end + end + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end diff --git a/lib/ruby_ui/shortcut_key/shortcut_key_docs.rb b/lib/ruby_ui/shortcut_key/shortcut_key_docs.rb new file mode 100644 index 00000000..ea1ee43e --- /dev/null +++ b/lib/ruby_ui/shortcut_key/shortcut_key_docs.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class Views::Docs::ShortcutKey < Views::Base + def view_template + component = "ShortcutKey" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Shortcut Key", description: "A component for displaying keyboard shortcuts.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Example", context: self) do + <<~RUBY + div(class: "flex flex-col items-center gap-y-4") do + ShortcutKey do + span(class: "text-xs") { "⌘" } + plain "K" + end + p(class: "text-muted-foreground text-sm text-center") { "Note this does not trigger anything, it is purely a visual prompt" } + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end diff --git a/lib/ruby_ui/sidebar/sidebar_docs.rb b/lib/ruby_ui/sidebar/sidebar_docs.rb new file mode 100644 index 00000000..165872fa --- /dev/null +++ b/lib/ruby_ui/sidebar/sidebar_docs.rb @@ -0,0 +1,176 @@ +# frozen_string_literal: true + +class Views::Docs::Sidebar < Views::Base + def view_template + component = "Sidebar" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Sidebar", description: "A composable, themeable and customizable sidebar component.") + + Heading(level: 2) { "Usage" } + + Alert do + info_icon + AlertTitle { "Requirements" } + AlertDescription { "The sidebar component depends on the following components:" } + ul(class: "list-disc list-inside") do + li do + InlineLink(href: docs_sheet_path, target: "_blank", class: "inline-flex items-center gap-2") do + span { "Sheet" } + external_icon_link + end + end + li do + div(class: "inline-flex items-center gap-2") do + InlineLink(href: docs_separator_path, target: "_blank") { "Separator" } + external_icon_link + end + end + 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: "Inset variant", src: "/docs/sidebar/inset", context: self) do + Views::Docs::Sidebar::InsetExample::CODE + end + + render Docs::VisualCodeExample.new(title: "Dialog variant", context: self) do + <<~RUBY + Dialog(data: {action: "ruby-ui--dialog:connect->ruby-ui--dialog#open"}) do + DialogTrigger do + Button { "Open Dialog" } + end + DialogContent(class: "grid overflow-hidden p-0 md:max-h-[500px] md:max-w-[700px] lg:max-w-[800px]") do + SidebarWrapper(class: "items-start") do + Sidebar(collapsible: :none, class: "hidden md:flex") do + SidebarContent do + SidebarGroup do + SidebarGroupContent do + SidebarMenu do + SidebarMenuItem do + SidebarMenuButton(as: :a, href: "#") do + search_icon() + span { "Search" } + end + end + SidebarMenuItem do + SidebarMenuButton(as: :a, href: "#", active: true) do + home_icon() + span { "Home" } + end + end + SidebarMenuItem do + SidebarMenuButton(as: :a, href: "#") do + inbox_icon() + span { "Inbox" } + end + end + end + end + end + end + end + main(class: "flex h-[480px] flex-1 flex-col overflow-hidden") do + end + end + end + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end + + def search_icon + svg( + xmlns: "http://www.w3.org/2000/svg", + width: "24", + height: "24", + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + stroke_width: "2", + stroke_linecap: "round", + stroke_linejoin: "round", + class: "lucide lucide-search" + ) do |s| + s.circle(cx: "11", cy: "11", r: "8") + s.path(d: "M21 21L16.7 16.7") + end + end + + def home_icon + svg( + xmlns: "http://www.w3.org/2000/svg", + width: "24", + height: "24", + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + stroke_width: "2", + stroke_linecap: "round", + stroke_linejoin: "round", + class: "lucide lucide-house" + ) do |s| + s.path(d: "M15 21v-8a1 1 0 0 0-1-1h-4a1 1 0 0 0-1 1v8") + 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") + end + end + + def inbox_icon + svg( + xmlns: "http://www.w3.org/2000/svg", + width: "24", + height: "24", + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + stroke_width: "2", + stroke_linecap: "round", + stroke_linejoin: "round", + class: "lucide lucide-inbox" + ) do |s| + s.polyline(points: "22 12 16 12 14 15 10 15 8 12 2 12") + 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") + end + end + + def external_icon_link + svg( + xmlns: "http://www.w3.org/2000/svg", + viewBox: "0 0 24 24", + fill: "none", + stroke: "currentColor", + stroke_width: "2", + stroke_linecap: "round", + stroke_linejoin: "round", + class: "lucide lucide-external-link-icon lucide-external-link size-3" + ) do |s| + s.path(d: "M15 3h6v6") + s.path(d: "M10 14 21 3") + s.path(d: "M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6") + end + end + + def info_icon + svg( + xmlns: "http://www.w3.org/2000/svg", + viewbox: "0 0 24 24", + fill: "currentColor", + class: "w-5 h-5" + ) do |s| + s.path( + fill_rule: "evenodd", + d: + "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", + clip_rule: "evenodd" + ) + end + end +end diff --git a/lib/ruby_ui/skeleton/skeleton_docs.rb b/lib/ruby_ui/skeleton/skeleton_docs.rb new file mode 100644 index 00000000..44d311f9 --- /dev/null +++ b/lib/ruby_ui/skeleton/skeleton_docs.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class Views::Docs::Skeleton < Views::Base + def view_template + component = "Skeleton" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Skeleton", description: "Use to show a placeholder while content is loading.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Example", context: self) do + <<~RUBY + div(class: "flex items-center space-x-4") do + Skeleton(class: "h-12 w-12 rounded-full") + div(class: "space-y-2") do + Skeleton(class: "h-4 w-[250px]") + Skeleton(class: "h-4 w-[200px]") + end + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end diff --git a/lib/ruby_ui/switch/switch_docs.rb b/lib/ruby_ui/switch/switch_docs.rb new file mode 100644 index 00000000..8f4dcdc7 --- /dev/null +++ b/lib/ruby_ui/switch/switch_docs.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +class Views::Docs::Switch < Views::Base + def view_template + component = "Switch" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Switch", description: "A control that allows the user to toggle between checked and not checked.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Default", context: self) do + <<~RUBY + Switch(name: "switch") + RUBY + end + + render Docs::VisualCodeExample.new(title: "Checked", context: self) do + <<~RUBY + Switch(name: "switch", checked: true) + RUBY + end + + render Docs::VisualCodeExample.new(title: "Disabled", context: self) do + <<~RUBY + Switch(name: "switch", disabled: true) + RUBY + end + + render Docs::VisualCodeExample.new(title: "Aria Disabled", context: self) do + <<~RUBY + Switch(name: "switch", aria: {disabled: "true"}) + RUBY + end + + render Docs::VisualCodeExample.new(title: "With flag include_hidden false", context: self) do + <<~RUBY + # Supports the creation of a hidden input to be used in forms inspired by the Ruby on Rails implementation of check_box. Default is true. + Switch(name: "switch", include_hidden: false) + RUBY + end + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end diff --git a/lib/ruby_ui/table/table_docs.rb b/lib/ruby_ui/table/table_docs.rb new file mode 100644 index 00000000..8ac4d8c0 --- /dev/null +++ b/lib/ruby_ui/table/table_docs.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +class Views::Docs::Table < Views::Base + Invoice = Struct.new(:identifier, :status, :method, :amount, keyword_init: true) + User = Struct.new(:avatar_url, :name, :username, :commits, :github_url, keyword_init: true) + + def view_template + component = "Table" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-8") do + render Docs::Header.new(title: "Table", description: "A responsive table component.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Without builder", context: self) do + <<~RUBY + Table do + TableCaption { "Employees at Acme inc." } + TableHeader do + TableRow do + TableHead { "Name" } + TableHead { "Email" } + TableHead { "Status" } + TableHead(class: "text-right") { "Role" } + end + end + TableBody do + invoices.each do |invoice| + TableRow do + TableCell(class: 'font-medium') { invoice.identifier } + TableCell { render_status_badge(invoice.status) } + TableCell { invoice.method } + TableCell(class: "text-right") { format_amount(invoice.amount) } + end + end + end + TableFooter do + TableRow do + TableHead(class: "font-medium", colspan: 3) { "Total" } + TableHead(class: "font-medium text-right") { format_amount(invoices.sum(&:amount)) } + end + end + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end + + private + + def invoices + [ + Invoice.new(identifier: "INV-0001", status: "Active", method: "Credit Card", amount: 100), + Invoice.new(identifier: "INV-0002", status: "Active", method: "Bank Transfer", amount: 230), + Invoice.new(identifier: "INV-0003", status: "Pending", method: "PayPal", amount: 350), + Invoice.new(identifier: "INV-0004", status: "Inactive", method: "Credit Card", amount: 100) + ] + end + + def users + [ + User.new(avatar_url: "https://avatars.githubusercontent.com/u/246692?v=4", name: "Joel Drapper", username: "joeldrapper", commits: 404), + User.new(avatar_url: "https://avatars.githubusercontent.com/u/33979976?v=4", name: "Alexandre Ruban", username: "alexandreruban", commits: 16), + User.new(avatar_url: "https://avatars.githubusercontent.com/u/77887?v=4", name: "Will Cosgrove", username: "willcosgrove", commits: 12), + User.new(avatar_url: "https://avatars.githubusercontent.com/u/3025661?v=4", name: "Stephann V.", username: "stephannv", commits: 8), + User.new(avatar_url: "https://avatars.githubusercontent.com/u/6411752?v=4", name: "Marco Roth", username: "marcoroth", commits: 8) + ] + end + + def github_link(user) + "https://github.com/#{user.username}" + end + + def github_icon + svg(viewbox: "0 0 438.549 438.549", class: "h-4 w-4") do |s| + s.path( + fill: "currentColor", + d: + "M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z" + ) + end + end + + def format_amount(amount) + "$#{amount}.00" + end + + def render_status_badge(status) + case status.downcase + when "active" + Badge(variant: :success, size: :sm) { status } + when "inactive" + Badge(variant: :destructive, size: :sm) { status } + when "pending" + Badge(variant: :warning, size: :sm) { status } + end + end +end diff --git a/lib/ruby_ui/tabs/tabs_docs.rb b/lib/ruby_ui/tabs/tabs_docs.rb new file mode 100644 index 00000000..33b6ff34 --- /dev/null +++ b/lib/ruby_ui/tabs/tabs_docs.rb @@ -0,0 +1,211 @@ +# frozen_string_literal: true + +class Views::Docs::Tabs < Views::Base + Repo = Struct.new(:github_url, :name, :stars, :version, keyword_init: true) + + def view_template + component = "Tabs" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Tabs", description: "A set of layered sections of content—known as tab panels—that are displayed one at a time.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Example", context: self) do + <<~RUBY + Tabs(default_value: "account", class: 'w-96') do + TabsList do + TabsTrigger(value: "account") { "Account" } + TabsTrigger(value: "password") { "Password" } + end + TabsContent(value: "account") do + div(class: "rounded-lg border p-6 space-y-4 bg-background text-foreground") do + div(class: "space-y-0") do + Text(size: "4", weight: "semibold") { "Account" } + Text(size: "2", class: "text-muted-foreground") { "Update your account details." } + end + end + end + TabsContent(value: "password") do + div(class: "rounded-lg border p-6 space-y-4 bg-background text-foreground") do + div do + Text(size: "4", weight: "semibold") { "Password" } + Text(size: "2", class: "text-muted-foreground") { "Change your password here. After saving, you'll be logged out." } + end + end + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Disabled", context: self) do + <<~RUBY + Tabs(default_value: "account", class: 'w-96') do + TabsList do + TabsTrigger(disabled: true, value: "account") { "Account" } + TabsTrigger(disabled: true, value: "password") { "Password" } + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Aria Disabled", context: self) do + <<~RUBY + Tabs(default_value: "account", class: 'w-96') do + TabsList do + TabsTrigger(aria: {disabled: "true"}, value: "account") { "Account" } + TabsTrigger(aria: {disabled: "true"}, value: "password") { "Password" } + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Full width", context: self) do + <<~RUBY + Tabs(default_value: "overview", class: 'w-96') do + TabsList(class: 'w-full grid grid-cols-2') do + TabsTrigger(value: "overview") do + book_icon + span(class: 'ml-2') { "Overview" } + end + TabsTrigger(value: "repositories") do + repo_icon + span(class: 'ml-2') { "Repositories" } + end + end + TabsContent(value: "overview") do + div(class: "rounded-lg border p-6 bg-background text-foreground flex justify-between space-x-4") do + Avatar do + AvatarImage(src: "https://avatars.githubusercontent.com/u/246692?v=4", alt: "joeldrapper") + AvatarFallback { "JD" } + end + div(class: "space-y-4") do + div do + Text(size: "4", weight: "semibold") { "Joel Drapper" } + Text(size: "2", class: "text-muted-foreground") { "Creator of Phlex Components. Ruby on Rails developer." } + end + Link(href: "https://github.com/joeldrapper", variant: :outline, size: :sm) do + github_icon + span(class: 'ml-2') { "View profile" } + end + end + end + end + TabsContent(value: "repositories") do + div(class: "rounded-lg border p-6 space-y-4 bg-background text-foreground") do + repo = repositories.first + Link(href: repo.github_url, variant: :link, class: "pl-0") { repo.name } + Badge { repo.version } + end + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Change default value", context: self) do + <<~RUBY + Tabs(default: "password", class: 'w-96') do + TabsList do + TabsTrigger(value: "account") { "Account" } + TabsTrigger(value: "password") { "Password" } + end + TabsContent(value: "account") do + div(class: "rounded-lg border p-6 space-y-4 bg-background text-foreground") do + div(class: "space-y-0") do + Text(size: "4", weight: "semibold") { "Account" } + Text(size: "2", class: "text-muted-foreground") { "Update your account details." } + end + end + end + TabsContent(value: "password") do + div(class: "rounded-lg border p-6 space-y-4 bg-background text-foreground") do + div do + Text(size: "4", weight: "semibold") { "Password" } + Text(size: "2", class: "text-muted-foreground") { "Change your password here. After saving, you'll be logged out." } + end + end + end + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end + + private + + def book_icon + svg( + xmlns: "http://www.w3.org/2000/svg", + fill: "none", + viewbox: "0 0 24 24", + stroke_width: "2", + stroke: "currentColor", + class: "w-4 h-4 text-muted-foreground" + ) do |s| + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: + "M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 016 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25" + ) + end + end + + def repo_icon + svg( + xmlns: "http://www.w3.org/2000/svg", + fill: "none", + viewbox: "0 0 24 24", + stroke_width: "2", + stroke: "currentColor", + class: "w-4 h-4 text-muted-foreground" + ) do |s| + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: + "M16.5 3.75V16.5L12 14.25 7.5 16.5V3.75m9 0H18A2.25 2.25 0 0120.25 6v12A2.25 2.25 0 0118 20.25H6A2.25 2.25 0 013.75 18V6A2.25 2.25 0 016 3.75h1.5m9 0h-9" + ) + end + end + + def github_icon + svg(viewbox: "0 0 438.549 438.549", class: "h-4 w-4") do |s| + s.path( + fill: "currentColor", + d: + "M409.132 114.573c-19.608-33.596-46.205-60.194-79.798-79.8-33.598-19.607-70.277-29.408-110.063-29.408-39.781 0-76.472 9.804-110.063 29.408-33.596 19.605-60.192 46.204-79.8 79.8C9.803 148.168 0 184.854 0 224.63c0 47.78 13.94 90.745 41.827 128.906 27.884 38.164 63.906 64.572 108.063 79.227 5.14.954 8.945.283 11.419-1.996 2.475-2.282 3.711-5.14 3.711-8.562 0-.571-.049-5.708-.144-15.417a2549.81 2549.81 0 01-.144-25.406l-6.567 1.136c-4.187.767-9.469 1.092-15.846 1-6.374-.089-12.991-.757-19.842-1.999-6.854-1.231-13.229-4.086-19.13-8.559-5.898-4.473-10.085-10.328-12.56-17.556l-2.855-6.57c-1.903-4.374-4.899-9.233-8.992-14.559-4.093-5.331-8.232-8.945-12.419-10.848l-1.999-1.431c-1.332-.951-2.568-2.098-3.711-3.429-1.142-1.331-1.997-2.663-2.568-3.997-.572-1.335-.098-2.43 1.427-3.289 1.525-.859 4.281-1.276 8.28-1.276l5.708.853c3.807.763 8.516 3.042 14.133 6.851 5.614 3.806 10.229 8.754 13.846 14.842 4.38 7.806 9.657 13.754 15.846 17.847 6.184 4.093 12.419 6.136 18.699 6.136 6.28 0 11.704-.476 16.274-1.423 4.565-.952 8.848-2.383 12.847-4.285 1.713-12.758 6.377-22.559 13.988-29.41-10.848-1.14-20.601-2.857-29.264-5.14-8.658-2.286-17.605-5.996-26.835-11.14-9.235-5.137-16.896-11.516-22.985-19.126-6.09-7.614-11.088-17.61-14.987-29.979-3.901-12.374-5.852-26.648-5.852-42.826 0-23.035 7.52-42.637 22.557-58.817-7.044-17.318-6.379-36.732 1.997-58.24 5.52-1.715 13.706-.428 24.554 3.853 10.85 4.283 18.794 7.952 23.84 10.994 5.046 3.041 9.089 5.618 12.135 7.708 17.705-4.947 35.976-7.421 54.818-7.421s37.117 2.474 54.823 7.421l10.849-6.849c7.419-4.57 16.18-8.758 26.262-12.565 10.088-3.805 17.802-4.853 23.134-3.138 8.562 21.509 9.325 40.922 2.279 58.24 15.036 16.18 22.559 35.787 22.559 58.817 0 16.178-1.958 30.497-5.853 42.966-3.9 12.471-8.941 22.457-15.125 29.979-6.191 7.521-13.901 13.85-23.131 18.986-9.232 5.14-18.182 8.85-26.84 11.136-8.662 2.286-18.415 4.004-29.263 5.146 9.894 8.562 14.842 22.077 14.842 40.539v60.237c0 3.422 1.19 6.279 3.572 8.562 2.379 2.279 6.136 2.95 11.276 1.995 44.163-14.653 80.185-41.062 108.068-79.226 27.88-38.161 41.825-81.126 41.825-128.906-.01-39.771-9.818-76.454-29.414-110.049z" + ) + end + end + + def star_icon + svg( + xmlns: "http://www.w3.org/2000/svg", + fill: "none", + viewbox: "0 0 24 24", + stroke_width: "2", + stroke: "currentColor", + class: "w-4 h-4 text-amber-500" + ) do |s| + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: + "M11.48 3.499a.562.562 0 011.04 0l2.125 5.111a.563.563 0 00.475.345l5.518.442c.499.04.701.663.321.988l-4.204 3.602a.563.563 0 00-.182.557l1.285 5.385a.562.562 0 01-.84.61l-4.725-2.885a.563.563 0 00-.586 0L6.982 20.54a.562.562 0 01-.84-.61l1.285-5.386a.562.562 0 00-.182-.557l-4.204-3.602a.563.563 0 01.321-.988l5.518-.442a.563.563 0 00.475-.345L11.48 3.5z" + ) + end + end + + def repositories + [ + Repo.new(github_url: "https://github.com/phlex-ruby/phlex", name: "phlex", stars: 961, version: "v1.8.1"), + Repo.new(github_url: "https://github.com/joeldrapper/green_dots", name: "green_dots", stars: 40, version: "1.0"), + Repo.new(github_url: "https://github.com/joeldrapper/literal", name: "literal", stars: 96, version: "v0.1.0") + ] + end +end diff --git a/lib/ruby_ui/textarea/textarea_docs.rb b/lib/ruby_ui/textarea/textarea_docs.rb new file mode 100644 index 00000000..ce83349a --- /dev/null +++ b/lib/ruby_ui/textarea/textarea_docs.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +class Views::Docs::Textarea < Views::Base + def view_template + component = "Textarea" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Textarea", description: "Displays a textarea field.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Textarea", context: self) do + <<~RUBY + div(class: "grid w-full max-w-sm items-center gap-1.5") do + Textarea(placeholder: "Textarea") + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Disabled", context: self) do + <<~RUBY + div(class: "grid w-full max-w-sm items-center gap-1.5") do + Textarea(disabled: true, placeholder: "Disabled") + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "Aria Disabled", context: self) do + <<~RUBY + div(class: "grid w-full max-w-sm items-center gap-1.5") do + Textarea(aria: {disabled: "true"}, placeholder: "Aria Disabled") + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "With FormField", context: self) do + <<~RUBY + div(class: "grid w-full max-w-sm items-center gap-1.5") do + FormField do + FormFieldLabel(for: "textarea") { "Textarea" } + FormFieldHint { "This is a textarea" } + Textarea(placeholder: "Textarea", id: "textarea") + FormFieldError() + end + end + RUBY + end + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end +end diff --git a/lib/ruby_ui/theme_toggle/theme_toggle_docs.rb b/lib/ruby_ui/theme_toggle/theme_toggle_docs.rb new file mode 100644 index 00000000..1740a924 --- /dev/null +++ b/lib/ruby_ui/theme_toggle/theme_toggle_docs.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +class Views::Docs::ThemeToggle < Views::Base + def view_template + component = "ThemeToggle" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Theme Toggle", description: "Toggle between dark/light theme.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "With icon", context: self) do + <<~RUBY + ThemeToggle do |toggle| + SetLightMode do + Button(variant: :ghost, icon: true) do + svg( + xmlns: "http://www.w3.org/2000/svg", + viewbox: "0 0 24 24", + fill: "currentColor", + class: "w-4 h-4" + ) do |s| + s.path( + d: + "M12 2.25a.75.75 0 01.75.75v2.25a.75.75 0 01-1.5 0V3a.75.75 0 01.75-.75zM7.5 12a4.5 4.5 0 119 0 4.5 4.5 0 01-9 0zM18.894 6.166a.75.75 0 00-1.06-1.06l-1.591 1.59a.75.75 0 101.06 1.061l1.591-1.59zM21.75 12a.75.75 0 01-.75.75h-2.25a.75.75 0 010-1.5H21a.75.75 0 01.75.75zM17.834 18.894a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 10-1.061 1.06l1.59 1.591zM12 18a.75.75 0 01.75.75V21a.75.75 0 01-1.5 0v-2.25A.75.75 0 0112 18zM7.758 17.303a.75.75 0 00-1.061-1.06l-1.591 1.59a.75.75 0 001.06 1.061l1.591-1.59zM6 12a.75.75 0 01-.75.75H3a.75.75 0 010-1.5h2.25A.75.75 0 016 12zM6.697 7.757a.75.75 0 001.06-1.06l-1.59-1.591a.75.75 0 00-1.061 1.06l1.59 1.591z" + ) + end + end + end + + SetDarkMode do + Button(variant: :ghost, icon: true) do + svg( + xmlns: "http://www.w3.org/2000/svg", + viewbox: "0 0 24 24", + fill: "currentColor", + class: "w-4 h-4" + ) do |s| + s.path( + fill_rule: "evenodd", + d: + "M9.528 1.718a.75.75 0 01.162.819A8.97 8.97 0 009 6a9 9 0 009 9 8.97 8.97 0 003.463-.69.75.75 0 01.981.98 10.503 10.503 0 01-9.694 6.46c-5.799 0-10.5-4.701-10.5-10.5 0-4.368 2.667-8.112 6.46-9.694a.75.75 0 01.818.162z", + clip_rule: "evenodd" + ) + end + end + end + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "With text", context: self) do + <<~RUBY + ThemeToggle do |toggle| + SetLightMode do + Button(variant: :primary) { "Light" } + end + + SetDarkMode do + Button(variant: :primary) { "Dark" } + end + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end diff --git a/lib/ruby_ui/tooltip/tooltip_docs.rb b/lib/ruby_ui/tooltip/tooltip_docs.rb new file mode 100644 index 00000000..5189728b --- /dev/null +++ b/lib/ruby_ui/tooltip/tooltip_docs.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +class Views::Docs::Tooltip < Views::Base + def view_template + component = "Tooltip" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Tooltip", description: "A popup that displays information related to an element when the element receives keyboard focus or the mouse hovers over it.") + + Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "Example", context: self) do + <<~RUBY + Tooltip do + TooltipTrigger do + Button(variant: :outline, icon: true) do + bookmark_icon + end + end + TooltipContent do + Text { "Add to library" } + end + end + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end + + private + + def bookmark_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" + ) do |s| + s.path( + stroke_linecap: "round", + stroke_linejoin: "round", + d: + "M17.593 3.322c1.1.128 1.907 1.077 1.907 2.185V21L12 17.25 4.5 21V5.507c0-1.108.806-2.057 1.907-2.185a48.507 48.507 0 0111.186 0z" + ) + end + end +end diff --git a/lib/ruby_ui/typography/typography_docs.rb b/lib/ruby_ui/typography/typography_docs.rb new file mode 100644 index 00000000..cf860dcf --- /dev/null +++ b/lib/ruby_ui/typography/typography_docs.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +class Views::Docs::Typography < Views::Base + def view_template + component = "Typography" + + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do + render Docs::Header.new(title: "Typography", description: "Sensible defaults to use for text.") + + Components.Heading(level: 2) { "Usage" } + + render Docs::VisualCodeExample.new(title: "h1", context: self) do + <<~RUBY + Heading(level: 1) { "This is an H1 title" } + RUBY + end + + render Docs::VisualCodeExample.new(title: "h2", context: self) do + <<~RUBY + Heading(level: 2) { "This is an H2 title" } + RUBY + end + + render Docs::VisualCodeExample.new(title: "h3", context: self) do + <<~RUBY + Heading(level: 3) { "This is an H3 title" } + RUBY + end + + render Docs::VisualCodeExample.new(title: "h4", context: self) do + <<~RUBY + Heading(level: 4) { "This is an H4 title" } + RUBY + end + + render Docs::VisualCodeExample.new(title: "p", context: self) do + <<~RUBY + Text { "This is an P tag" } + RUBY + end + + render Docs::VisualCodeExample.new(title: "Inline Link", context: self) do + <<~RUBY + Text(class: 'text-center') do + plain "Checkout our " + InlineLink(href: docs_installation_path) { "installation instructions" } + plain " to get started." + end + RUBY + end + + render Docs::VisualCodeExample.new(title: "List", context: self) do + <<~RUBY + Components.TypographyList(items: [ + 'Phlex is fast', + 'Phlex is easy to use', + 'Phlex is awesome', + ]) + RUBY + end + + render Docs::VisualCodeExample.new(title: "Numbered List", context: self) do + <<~RUBY + Components.TypographyList(items: [ + 'Copy', + 'Paste', + 'Customize', + ], numbered: true) + RUBY + end + + render Docs::VisualCodeExample.new(title: "Inline Code", context: self) do + <<~RUBY + InlineCode { "This is an inline code block" } + RUBY + end + + render Docs::VisualCodeExample.new(title: "Lead", context: self) do + <<~RUBY + Text(as: "p", size: "5", weight: "muted") { "A modal dialog that interrupts the user with important content and expects a response." } + RUBY + end + + render Docs::VisualCodeExample.new(title: "Large", context: self) do + <<~RUBY + Text(size: "4", weight: "semibold") { "Are you sure absolutely sure?" } + RUBY + end + + render Docs::VisualCodeExample.new(title: "Small", context: self) do + <<~RUBY + Text(size: "sm") { "Email address" } + RUBY + end + + render Docs::VisualCodeExample.new(title: "Muted", context: self) do + <<~RUBY + Text(size: "2", class: "text-muted-foreground") { "Enter your email address." } + RUBY + end + + render Components::ComponentSetup::Tabs.new(component_name: component) + + render Docs::ComponentsTable.new(component_files(component)) + end + end +end