The project is in a healthy, maintained state
Adds a Streamfield component to Spina
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

>= 2.1.0
 Project Readme

Spina::Streamfield

A StreamField component for Spina

Installation

# Gemfile
gem 'Spina' # prerequisite
gem 'spina-streamfield'

What is this thing?

It's basically a Ruby version of the StreamField component in the Python Wagtail CMS, but for Spina CMS! It provides an open-ended page component where the admin content creator can mixmatch any other Spina component in a sort of list, even custom components that you build in your app.

streamfield_demo.gif

It was created because I disliked the way Trix stored media like images and YouTube links in the RichText field. Links were hard coded, making them difficult to mass edit or customize how they are displayed.

Here's how StreamField works in Wagtail. This one is very similar in concept:

https://youtu.be/9YLBJC1rPnk?si=EliQ_gNI89cXhinQ

Usage

Base components that are registered are MultiLine, RichText, and Image. To make other components available in the Streamfield:

# config/initializers/spina.rb

# Custom YouTube component in the hosting program  
Spina::Part.register(Spina::Parts::YoutubeVideo)

# Register custom StreamField block types.
# Runs after class reload (which resets @component_types to defaults), so additions are re-applied on each reload.
Spina::Parts::StreamField.register_component("YouTube Video", Spina::Parts::YoutubeVideo)
# Spina::Parts::StreamField.unregister_component("Image")  # example: remove a default


# config/initializers/themes/default.rb
theme.parts = [
  {name: "streamfield", title: "Article Body", part_type: "Spina::Parts::StreamField"},
]

theme.view_templates = [
  {name: "page_parts_demo", title: "Page Parts Demo", parts: %w[streamfield]}
]

In your display template:

<%= # app/views/defaults/pages/page_parts_demo.html.erb %>

<% content(:streamfield)&.each do |item| %>
  <% if item.part_type == "Spina::Parts::MultiLine" %>
    <%= markdown(item.content_part.content) %>
  <% elsif item.part_type == "Spina::Parts::YoutubeVideo" %>
    <figure class="py-2">
      <%= render(partial: 'default/pages/youtube_video', locals: { youtube_part: item.content_part }) %>
    </figure>
  <% elsif item.part_type == "Spina::Parts::Image" %>
    <figure class="py-2">
      <%= content.image_tag(item.content_part, {}, { style: "max-width: 600px;" }) %>
      <% if item.content_part.alt.present? %>
        <figcaption><%= item.content_part.alt %></figcaption>
      <% end %>
    </figure>
  <% end %>
<% end %>

Notice that in the example above I have a Markdown helper that allows me to use Markdown in the MultiLine component:

module ApplicationHelper
  def markdown(text_page_part)
    Kramdown::Document.new(text_page_part.to_s).to_html.html_safe
  end
end

Contributing

Open a PR or Issue if you want, or not

License

The gem is available as open source under the terms of the MIT License.