Processor for styled blockquotes

rails app:template LOCATION='https://perron.railsdesigner.com/library/styled-blockquotes-processor/template.rb'

This snippet adds a processor to transform blockquotes into styled HTML elements, like seen on GitHub. It supports the types: note, tip, important, warning and caution.

The processor detects blockquotes starting with [!type] markers and transforms them into styled blockquotes with custom classes and optional icons using Rails Icons.

Usage

> [!note]
> This is a note with useful information.

> [!warning]
> This is a warning that requires attention.

> [!tip]
> This is a helpful tip for users.

Template source

create_file "app/processors/styled_blockquote_processor.rb", <<~RUBY
  class StyledBlockquoteProcessor < Perron::HtmlProcessor::Base
    # uncomment if you use Rails Icons, see: https://github.com/Rails-Designer/rails_icons/
    # include RailsIcons::Helpers::IconHelper

    def process
      @html.css("blockquote").each { transform_to_styled it }
    end

    private


    # Add an `icon` key with a Rails Icons name to include an icon
    # Example: "note" => { class: "alert alert-note", icon: "information-circle" }
    STYLES = {
      "note" => {
        class: "alert alert-note"
      },

      "tip" => {
        class: "alert alert-tip"
      },

      "important" => {
        class: "alert alert-important"
      },

      "warning" => {
        class: "alert alert-warning"
      },

      "caution" => {
        class: "alert alert-caution"
      }
    }

    def transform_to_styled(blockquote)
      paragraph = blockquote.at_css("p")
      text = paragraph&.inner_html&.strip
      marker = text&.match(/^\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\]/i)

      return unless marker

      type = marker[1].downcase
      style = STYLES[type]

      paragraph.inner_html = paragraph.inner_html.sub(/^\[!#{type}\]\s*/i, "").sub(/^(<br>\s*)+/, "")
      blockquote["class"] = style[:class]

      blockquote.prepend_child(icon(style[:icon])) if style[:icon] && respond_to?(:icon)
    end
  end
end