|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +class Views::Docs::Bubble < Views::Base |
| 4 | + def view_template |
| 5 | + component = "Bubble" |
| 6 | + |
| 7 | + div(class: "max-w-2xl mx-auto w-full py-10 space-y-10") do |
| 8 | + render Docs::Header.new(title: "Bubble", description: "A chat bubble surface for displaying conversational content, with variants, alignment, grouping, and reactions.") |
| 9 | + |
| 10 | + Heading(level: 2) { "Usage" } |
| 11 | + |
| 12 | + render Docs::VisualCodeExample.new(title: "Default", context: self) do |
| 13 | + <<~RUBY |
| 14 | + Bubble(align: :end) do |
| 15 | + BubbleContent { "Hey there! what's up?" } |
| 16 | + end |
| 17 | + RUBY |
| 18 | + end |
| 19 | + |
| 20 | + render Docs::VisualCodeExample.new(title: "Conversation", context: self) do |
| 21 | + <<~RUBY |
| 22 | + div(class: "flex flex-col gap-8") do |
| 23 | + Bubble(align: :end) do |
| 24 | + BubbleContent { "Hey there! what's up?" } |
| 25 | + end |
| 26 | + BubbleGroup do |
| 27 | + Bubble(variant: :muted) do |
| 28 | + BubbleContent { "Hey! Want to see chat bubbles?" } |
| 29 | + end |
| 30 | + Bubble(variant: :muted) do |
| 31 | + BubbleContent { "I can group messages, switch sides, and keep the whole thread easy to scan." } |
| 32 | + BubbleReactions(role: "img", aria_label: "Reaction: thumbs up") do |
| 33 | + span { "👍" } |
| 34 | + end |
| 35 | + end |
| 36 | + end |
| 37 | + Bubble(align: :end) do |
| 38 | + BubbleContent { "Sure. Hit me with your best demo." } |
| 39 | + end |
| 40 | + end |
| 41 | + RUBY |
| 42 | + end |
| 43 | + |
| 44 | + Heading(level: 2) { "Variants" } |
| 45 | + |
| 46 | + render Docs::VisualCodeExample.new(title: "Variants", context: self) do |
| 47 | + <<~RUBY |
| 48 | + div(class: "flex flex-col gap-4 w-full") do |
| 49 | + Bubble(variant: :default) { BubbleContent { "Default" } } |
| 50 | + Bubble(variant: :secondary) { BubbleContent { "Secondary" } } |
| 51 | + Bubble(variant: :muted) { BubbleContent { "Muted" } } |
| 52 | + Bubble(variant: :tinted) { BubbleContent { "Tinted" } } |
| 53 | + Bubble(variant: :outline) { BubbleContent { "Outline" } } |
| 54 | + Bubble(variant: :ghost) { BubbleContent { "Ghost — unframed, full width for assistant text or markdown." } } |
| 55 | + Bubble(variant: :destructive) { BubbleContent { "Destructive — something went wrong." } } |
| 56 | + end |
| 57 | + RUBY |
| 58 | + end |
| 59 | + |
| 60 | + Heading(level: 2) { "Alignment" } |
| 61 | + |
| 62 | + render Docs::VisualCodeExample.new(title: "Start and end", context: self) do |
| 63 | + <<~RUBY |
| 64 | + div(class: "flex flex-col gap-4 w-full") do |
| 65 | + Bubble(align: :start, variant: :muted) do |
| 66 | + BubbleContent { "Aligned to the start (receiver)." } |
| 67 | + end |
| 68 | + Bubble(align: :end) do |
| 69 | + BubbleContent { "Aligned to the end (sender)." } |
| 70 | + end |
| 71 | + end |
| 72 | + RUBY |
| 73 | + end |
| 74 | + |
| 75 | + Heading(level: 2) { "Reactions" } |
| 76 | + |
| 77 | + render Docs::VisualCodeExample.new(title: "Reactions", context: self) do |
| 78 | + <<~RUBY |
| 79 | + div(class: "flex flex-col gap-10 w-full py-6") do |
| 80 | + Bubble(variant: :muted) do |
| 81 | + BubbleContent { "Reactions anchor to the bubble edge." } |
| 82 | + BubbleReactions(role: "img", aria_label: "Reactions: thumbs up, fire, eyes, and 2 more") do |
| 83 | + span { "👍" } |
| 84 | + span { "🔥" } |
| 85 | + span { "👀" } |
| 86 | + span { "+2" } |
| 87 | + end |
| 88 | + end |
| 89 | + Bubble(align: :end) do |
| 90 | + BubbleContent { "Place them on top and to the start too." } |
| 91 | + BubbleReactions(side: :top, align: :start, role: "img", aria_label: "Reaction: heart") do |
| 92 | + span { "❤️" } |
| 93 | + end |
| 94 | + end |
| 95 | + end |
| 96 | + RUBY |
| 97 | + end |
| 98 | + |
| 99 | + Heading(level: 2) { "Group" } |
| 100 | + |
| 101 | + render Docs::VisualCodeExample.new(title: "Bubble group", context: self) do |
| 102 | + <<~RUBY |
| 103 | + BubbleGroup do |
| 104 | + Bubble(variant: :muted) { BubbleContent { "First message in the group." } } |
| 105 | + Bubble(variant: :muted) { BubbleContent { "Second one, tighter spacing." } } |
| 106 | + Bubble(variant: :muted) { BubbleContent { "Third, all stacked together." } } |
| 107 | + end |
| 108 | + RUBY |
| 109 | + end |
| 110 | + |
| 111 | + Heading(level: 2) { "Link or button bubble" } |
| 112 | + |
| 113 | + render Docs::VisualCodeExample.new(title: "Interactive content", context: self) do |
| 114 | + <<~RUBY |
| 115 | + div(class: "flex flex-col gap-4 w-full") do |
| 116 | + Bubble(align: :end) do |
| 117 | + BubbleContent(as: :a, href: "#") { "Tap to open the link →" } |
| 118 | + end |
| 119 | + Bubble(variant: :outline) do |
| 120 | + BubbleContent(as: :button, type: "button") { "Retry sending" } |
| 121 | + end |
| 122 | + end |
| 123 | + RUBY |
| 124 | + end |
| 125 | + |
| 126 | + Heading(level: 2) { "With Tooltip" } |
| 127 | + |
| 128 | + render Docs::VisualCodeExample.new(title: "Reveal metadata on hover", context: self) do |
| 129 | + <<~RUBY |
| 130 | + Tooltip do |
| 131 | + TooltipTrigger(class: "w-fit") do |
| 132 | + Bubble(variant: :muted, class: "max-w-none") do |
| 133 | + BubbleContent { "Read 9:41 AM" } |
| 134 | + end |
| 135 | + end |
| 136 | + TooltipContent do |
| 137 | + Text { "Delivered and read" } |
| 138 | + end |
| 139 | + end |
| 140 | + RUBY |
| 141 | + end |
| 142 | + |
| 143 | + Heading(level: 2) { "With Popover" } |
| 144 | + |
| 145 | + render Docs::VisualCodeExample.new(title: "Surface details on demand", context: self) do |
| 146 | + <<~RUBY |
| 147 | + Popover do |
| 148 | + PopoverTrigger do |
| 149 | + Bubble(variant: :destructive, class: "max-w-none") do |
| 150 | + BubbleContent { "Message failed to send" } |
| 151 | + end |
| 152 | + end |
| 153 | + PopoverContent(class: "w-64") do |
| 154 | + Text(weight: :semibold) { "Delivery error" } |
| 155 | + Text(size: :sm, class: "text-muted-foreground") { "The recipient's inbox is full. Try again later." } |
| 156 | + end |
| 157 | + end |
| 158 | + RUBY |
| 159 | + end |
| 160 | + |
| 161 | + render Components::ComponentSetup::Tabs.new(component_name: component) |
| 162 | + |
| 163 | + # components |
| 164 | + render Docs::ComponentsTable.new(component_files(component)) |
| 165 | + end |
| 166 | + end |
| 167 | +end |
0 commit comments