Skip to main content

Card component processor

to run in your site's root directory
View template source
gem "perron" unless File.read("Gemfile").include?("perron")

after_bundle do
  unless File.exist?("config/initializers/perron.rb")
    rails_command "perron:install"
  end

  create_file "app/processors/card_processor.rb", <<~'TEXT', force: true
class CardProcessor < Perron::HtmlProcessor::Base
  include ActionView::Helpers::UrlHelper

  def process
    @html.css("p").each { cardify it }
  end

  private

  def cardify(node)
    content = node.content

    return unless content.match?(/\[!card/i)

    replace_outer node, with: content.gsub(/\[!card\s+([^\]]+)\]/i) { card resource($1) }
  end

  def card(resource)
    link_to Rails.application.routes.url_helpers.resource_path(resource), class: "card" do
      safe_join([
        tag.h5(resource.metadata.title, class: "title"),

        tag.p(resource.metadata.description, class: "description"),

        tag.time(resource.published_at, datetime: resource.published_at, class: "timestamp")
      ])
    end
  end

  def resource(id) = Content::Article.find!(id)

  def replace_outer(node, with:)
    node.replace(Nokogiri::XML::DocumentFragment.parse(with))
  end
end

TEXT

create_file "app/processors/card_processor.rb", <<~'TEXT', force: true
class CardProcessor < Perron::HtmlProcessor::Base
  include ActionView::Helpers::UrlHelper

  def process
    @html.css("p").each { cardify it }
  end

  private

  def cardify(node)
    content = node.content

    return unless content.match?(/\[!card/i)

    replace_outer node, with: content.gsub(/\[!card\s+([^\]]+)\]/i) { card resource($1) }
  end

  def card(resource)
    link_to Rails.application.routes.url_helpers.resource_path(resource), class: "card" do
      safe_join([
        tag.h5(resource.metadata.title, class: "title"),

        tag.p(resource.metadata.description, class: "description"),

        tag.time(resource.published_at, datetime: resource.published_at, class: "timestamp")
      ])
    end
  end

  def resource(id) = Content::Article.find!(id)

  def replace_outer(node, with:)
    node.replace(Nokogiri::XML::DocumentFragment.parse(with))
  end
end

TEXT
end

This snippet adds a processor that allows adding linking to resources in your markdown content. Display it like a card or however you want.

Usage: [!card my-first-post] where my-first-post is the slug of Content::Post. You can change the resource class to any other resource class.

Use cases

  • content highlights; emphasize key posts or updates
  • interactive elements; engage readers with card displays
  • cross-promotion; suggest related posts dynamically within your content