Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ gem "decant"
gem "kramdown"
gem "kramdown-parser-gfm"
gem "lookbook", ">= 2.3.11"
gem "rails_autolink"
26 changes: 21 additions & 5 deletions app/components/flowbite/breadcrumb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,41 @@
module Flowbite
# Renders a breadcrumb navigation component.
#
# See https://flowbite.com/docs/components/breadcrumb/
#
# Use {Flowbite::Breadcrumb} and the child {Flowbite::Breadcrumb::Item} components to create and indicate a series of page structure and URLs to help the user navigate through the website.
# Use {Flowbite::Breadcrumb} and the child {Flowbite::Breadcrumb::Item}
# components to create and indicate a series of page structure and URLs to
# help the user navigate through the website.
#
# Breadcrumbs consist of the following components:
#
# - {Flowbite::Breadcrumb}: Container for breadcrumb items.
# - {Flowbite::Breadcrumb::HomeIcon}: Home icon for the first breadcrumb item.
# - {Flowbite::Breadcrumb::SeparatorIcon}: Separator between breadcrumb items.
# - {Flowbite::Breadcrumb::Item}: An individual breadcrumb item.
# - {Flowbite::Breadcrumb::Item::Current}: An invidual breadcrumb item without a link, usually used for the current page in the breadcrumb trail.
# - {Flowbite::Breadcrumb::Item::First}: An individual breadcrumb item with a home icon on it.
# - {Flowbite::Breadcrumb::Item::Current}: An individual breadcrumb item
# without a link, usually used for the current page in the breadcrumb trail.
# - {Flowbite::Breadcrumb::Item::First}: An individual breadcrumb item with a
# home icon on it.
#
# @example Usage
# <%= render(Flowbite::Breadcrumb.new) do |breadcrumb| %>
# <% breadcrumb.with_item do %>
# <%= render(Flowbite::Breadcrumb::Item::First.new(href: "/")) { "Root page" } %>
# <% end %>
# <% breadcrumb.with_item do %>
# <%= render(Flowbite::Breadcrumb::Item.new(href: "/projects")) { "Parent page" } %>
# <% end %>
# <% breadcrumb.with_item do %>
# <%= render(Flowbite::Breadcrumb::Item::Current.new) { "Current Page" } %>
# <% end %>
# <% end %>
#
# @viewcomponent_slot [Flowbite::Breadcrumb::Item] items The items of the
# breadcrumb trail. Use {Flowbite::Breadcrumb::Item::First} for the first
# item to get a home icon, and {Flowbite::Breadcrumb::Item::Current} for the
# last item to render it without a link.
#
# @lookbook_embed BreadcrumbPreview
# @see https://flowbite.com/docs/components/breadcrumb/
class Breadcrumb < ViewComponent::Base
renders_many :items

Expand Down
3 changes: 1 addition & 2 deletions app/components/flowbite/card.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
module Flowbite
# Renders a card element.
#
# See https://flowbite.com/docs/components/cards/
#
# To render a title in the card, use the title argument or the title slot.
#
# @example Using the title slot
Expand All @@ -18,6 +16,7 @@ module Flowbite
# @viewcomponent_slot [Flowbite::Card::Title] title The title of the card,
# rendered at the top. Use +with_title+ to set custom content.
#
# @see https://flowbite.com/docs/components/cards/
# @lookbook_embed CardPreview
class Card < ViewComponent::Base
renders_one :title
Expand Down
11 changes: 7 additions & 4 deletions app/components/flowbite/input.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@ module Flowbite
#
# Use this when you want to render an input field on its own without any
# surrounding elements, i.e. as a building block in more complex input
# components.
#
# To render a complete input field with labels and error messages, use
# {Flowbite::InputField} instead.
# components. To render a complete input field with labels and error messages,
# use {Flowbite::InputField} instead.
#
# By default this renders a text input field. To render other types of input
# fields, use one of the subclasses, such as {Flowbite::Input::Checkbox} or
# {Flowbite::Input::Textarea}.
#
# @example Usage
# <%= render(Flowbite::Input::Email.new(attribute: :email, form: form)) %>
#
# @lookbook_embed InputPreview
class Input < ViewComponent::Base
SIZES = {
sm: ["px-2.5", "py-2", "text-sm"],
Expand Down
2 changes: 0 additions & 2 deletions app/components/flowbite/input_field.rb
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ module Flowbite
# {Flowbite::Input} instead and one of its subclasses.
#
# @example Basic usage
#
# <% form_for @person do |form| %>
# <%= render(
# Flowbite::InputField::Number.new(
Expand All @@ -31,7 +30,6 @@ module Flowbite
# <% end %>
#
# @example Kitchen sink
#
# <% form_for @person do |form| %>
# <%= render(
# Flowbite::InputField::Number.new(
Expand Down
15 changes: 8 additions & 7 deletions app/components/flowbite/toast.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@
module Flowbite
# Renders a toast notification element.
#
# See https://flowbite.com/docs/components/toast/
#
# @param class [Array<String>] Additional CSS classes for the toast container.
# @param dismissible [Boolean] Whether the toast can be dismissed (default: true).
# @param message [String] The message to display in the toast.
# @param options [Hash] Additional HTML options for the toast container.
# @param style [Symbol] The color style of the toast (:default, :success, :danger, :warning).
# @example Usage
# <%= render(Flowbite::Toast.new(message: "Something has happened!")) %>
#
# @see https://flowbite.com/docs/components/toast/
# @lookbook_embed ToastPreview
class Toast < ViewComponent::Base
class << self
Expand All @@ -21,6 +17,11 @@ def classes

attr_reader :dismissible, :message, :options, :style

# @param class [Array<String>] Additional CSS classes for the toast container.
# @param dismissible [Boolean] Whether the toast can be dismissed (default: true).
# @param message [String] The message to display in the toast.
# @param options [Hash] Additional HTML options for the toast container.
# @param style [Symbol] The color style of the toast (:default, :success, :danger, :warning).
def initialize(message:, dismissible: true, style: :default, class: nil, **options)
@message = message
@style = style
Expand Down
10 changes: 5 additions & 5 deletions demo/.yardoc/checksums
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
app/components/flowbite/card.rb 6f248428402ae1a72982cd0cde3acd77a6f43308
app/components/flowbite/card.rb 9fe54b52bc9d177c2ec1d9e68e0a397b8a327744
app/components/flowbite/link.rb 1516522405f7cf2021913a4ebbb792f4ae386c16
app/components/flowbite/input.rb 6fbe49459aa61f71e7fb72688372223189167ac7
app/components/flowbite/input.rb df2ae5f59a7d33a635599632386053f999f65919
app/components/flowbite/style.rb ef063360cc99cd7a6b8e67a7693326bb5dfb0e42
app/components/flowbite/toast.rb 5847b4e1b7387f27f7bc65c8098f132b9fdf0c86
app/components/flowbite/toast.rb 6b822405dd55d87d56979e6cfba55e8f73965047
app/components/flowbite/button.rb 6ae7681d3b842d73aa99cddfa5a9b107ede7fea4
app/components/flowbite/styles.rb 929c42e428ba5a8e16efacaae0f35380e2f5f95c
app/components/flowbite/input/url.rb f1046824f9b06c8df8e0f567979321b82baac6fa
app/components/flowbite/breadcrumb.rb 95b9f165154d4a3e4029fe33b7663d7d7302ba98
app/components/flowbite/breadcrumb.rb c69ffb465b6e7f2489d4ac9a928e08bdf252fe99
app/components/flowbite/card/title.rb 8067aa1e027c725896b063b67364aecfbf2f7d4e
app/components/flowbite/input/date.rb 3b47f26b5622267e772c0d42d37655336ddf0169
app/components/flowbite/input/file.rb 538334cde553b4c74456716e35353c6c26467646
Expand All @@ -16,7 +16,7 @@ app/components/flowbite/button/pill.rb 5200da68b3fdd353db3780550b932f4037a7c999
app/components/flowbite/input/email.rb c89f74f38cdefce5c05bac458b39d56a9ba4aa35
app/components/flowbite/input/label.rb d71e843b267f35f10c3627e950408493a9afa97c
app/components/flowbite/input/phone.rb 0dfe3e9a83c4fb9f558405a20601649c7b08922a
app/components/flowbite/input_field.rb 529d2ff113db8644c345e32994e62366479c8cb0
app/components/flowbite/input_field.rb 8ef98ace7d4ccb4f474d3063cf48cc5c83cd8068
app/components/flowbite/input/number.rb a33580788ad91308b85955fdb44d37883329dd4e
app/components/flowbite/input/select.rb 9f1a6406efdda2e29d479117a35c2a924bd888c2
app/components/flowbite/button/outline.rb 2829cf352a03c00dd99a56a05181c4e1a6794d18
Expand Down
Binary file modified demo/.yardoc/objects/root.dat
Binary file not shown.
1 change: 1 addition & 0 deletions demo/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ gem "decant"
gem "kramdown"
gem "kramdown-parser-gfm"
gem "lookbook", ">= 2.3.11"
gem "rails_autolink"

group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
Expand Down
5 changes: 5 additions & 0 deletions demo/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,10 @@ GEM
rails-html-sanitizer (1.6.2)
loofah (~> 2.21)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
rails_autolink (1.1.8)
actionview (> 3.1)
activesupport (> 3.1)
railties (> 3.1)
railties (8.0.2.1)
actionpack (= 8.0.2.1)
activesupport (= 8.0.2.1)
Expand Down Expand Up @@ -305,6 +309,7 @@ DEPENDENCIES
propshaft
puma (>= 5.0)
rails (~> 8.0.2)
rails_autolink
sqlite3 (>= 2.1)
tailwindcss-rails (~> 4.3)
tzinfo-data
Expand Down
1 change: 1 addition & 0 deletions demo/app/components/docs/code_example.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<pre><code class="block bg-neutral-tertiary px-4 py-2 rounded-lg"><%= content %></code></pre>
4 changes: 4 additions & 0 deletions demo/app/components/docs/code_example.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# frozen_string_literal: true

class Docs::CodeExample < ViewComponent::Base
end
5 changes: 5 additions & 0 deletions demo/app/components/docs/headline.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Docs::Headline < ViewComponent::Base
def call
content_tag(tag, content, class: classes)
end
end
9 changes: 9 additions & 0 deletions demo/app/components/docs/headline/h1.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Docs::Headline::H1 < Docs::Headline
def classes
"mb-4 text-4xl tracking-tight font-bold text-heading"
end

def tag
:h1
end
end
9 changes: 9 additions & 0 deletions demo/app/components/docs/headline/h2.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Docs::Headline::H2 < Docs::Headline
def classes
"mb-4 mt-8 text-2xl font-bold text-heading"
end

def tag
:h2
end
end
9 changes: 9 additions & 0 deletions demo/app/components/docs/headline/h3.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Docs::Headline::H3 < Docs::Headline
def classes
"mt-4 mb-2 text-xl font-bold text-heading"
end

def tag
:h3
end
end
9 changes: 9 additions & 0 deletions demo/app/components/docs/headline/h4.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Docs::Headline::H4 < Docs::Headline
def classes
"mt-4 text-md font-bold text-heading"
end

def tag
:h4
end
end
49 changes: 35 additions & 14 deletions demo/app/controllers/docs/components_controller.rb
Original file line number Diff line number Diff line change
@@ -1,18 +1,7 @@
module Docs
class ComponentsController < ApplicationController
class Yard
def code_object(class_name)
::YARD::Registry.load!(yardoc_path) if ::YARD::Registry.all.empty?
::YARD::Registry.at(class_name)
end

def yardoc_path
Rails.root.join(".yardoc")
end
end

def show
@code_object = Yard.new.code_object(params[:id])
@code_object = Yard.code_object(params[:id])
raise ActiveRecord::RecordNotFound if @code_object.nil?

@child_classes = @code_object.children.select { |c| c.is_a?(YARD::CodeObjects::ClassObject) }.sort_by(&:name)
Expand All @@ -23,9 +12,12 @@ def show
[]
end
@examples = @code_object.tags(:example)
@lookbook_embeds = @code_object.tags(:lookbook_embed)
@viewcomponent_slots = @code_object.tags(:viewcomponent_slot)

lookbook_embeds = @code_object.tags(:lookbook_embed)
@introduction_preview = find_example_preview(lookbook_embeds)
@previews = find_non_example_previews(lookbook_embeds)

respond_to do |format|
format.html
format.md
Expand All @@ -37,14 +29,43 @@ def show
helper_method def all_components
return @all_components if @all_components

flowbite = Yard.new.code_object("Flowbite")
flowbite = Yard.code_object("Flowbite")
child_classes = flowbite.children.select { |child|
child.type == :class && child.inheritance_tree.map(&:path).include?("ViewComponent::Base")
}

@all_components = child_classes.sort_by(&:name)
end

# Returns the Lookbook preview with a scenario named "example"
#
# @return [Lookbook::Preview, nil]
def find_example_preview(lookbook_embeds)
return nil if lookbook_embeds.empty?

preview_class = lookbook_embeds.first.text.strip
return nil if preview_class.blank?

preview = Lookbook::Engine.previews.find_by_preview_class(preview_class)
return nil unless preview

preview if preview.scenarios.any? { |s| s.name == "example" }
end

# @return [Array<Lookbook::Entity>]
def find_non_example_previews(lookbook_embeds)
return [] if lookbook_embeds.empty?

preview_class = lookbook_embeds.first.text.strip
return [] if preview_class.blank?

preview_entity = Lookbook::Engine.previews.find_by_preview_class(preview_class)
return [] unless preview_entity

scenarios = preview_entity.scenarios
scenarios.reject { |s| s.name == "example" }
end

helper_method def rubydoc_url(code_object)
name = code_object.path
slug = name.gsub("::", "/")
Expand Down
73 changes: 73 additions & 0 deletions demo/app/helpers/formatting_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
require "rails_autolink"

module FormattingHelper
class DocstringRenderer
include YARD::Templates::Helpers::BaseHelper
include YARD::Templates::Helpers::HtmlHelper

Options = Data.define(:markup)

attr_reader :view_context

def initialize(content, view_context:, code_object: nil)
@content = content
@code_object = code_object
@view_context = view_context
end

# Called by YARD::Templates::Helpers::HtmlHelper#htmlify to render the
# docstring content. The default implementation simply returns the content
# as is, but you can override this method to provide custom rendering logic
# based on the specified markup format.
def html_markup_markdown(content)
return "" unless content
return "" unless content.strip.present?

output = Kramdown::Document.new(content, input: "GFM").to_html
remove_line_breaks(output)
end

def render
htmlify(@content)
end

private

def object
# Required by YARD::Templates::Helpers::HtmlHelper#resolve_links
@code_object
end

def options
@options ||= Options.new(
markup: :markdown
)
end

def remove_line_breaks(text)
text.gsub("<br />", " ")
end

def linkify(name, title)
code_object = Yard.code_object(name)
if code_object
view_context.link_to(title || name, view_context.docs_component_path(code_object.path))
else
title || name
end
end
end

def render_docstring(content, code_object: nil)
html = DocstringRenderer.new(
content,
code_object: code_object,
view_context: self
).render.html_safe
auto_link(html)
end

def render_markdown(content)
Kramdown::Document.new(content, input: "GFM").to_html.html_safe
end
end
Loading