spina 1.1.1 → 2.0.0.alpha

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of spina might be problematic. Click here for more details.

Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +23 -244
  3. data/app/assets/fonts/spina/Metropolis-Black.woff2 +0 -0
  4. data/app/assets/fonts/spina/Metropolis-BlackItalic.woff2 +0 -0
  5. data/app/assets/fonts/spina/Metropolis-Bold.woff2 +0 -0
  6. data/app/assets/fonts/spina/Metropolis-BoldItalic.woff2 +0 -0
  7. data/app/assets/fonts/spina/Metropolis-ExtraBold.woff2 +0 -0
  8. data/app/assets/fonts/spina/Metropolis-ExtraBoldItalic.woff2 +0 -0
  9. data/app/assets/fonts/spina/Metropolis-ExtraLight.woff2 +0 -0
  10. data/app/assets/fonts/spina/Metropolis-ExtraLightItalic.woff2 +0 -0
  11. data/app/assets/fonts/spina/Metropolis-Light.woff2 +0 -0
  12. data/app/assets/fonts/spina/Metropolis-LightItalic.woff2 +0 -0
  13. data/app/assets/fonts/spina/Metropolis-Medium.woff2 +0 -0
  14. data/app/assets/fonts/spina/Metropolis-MediumItalic.woff2 +0 -0
  15. data/app/assets/fonts/spina/Metropolis-Regular.woff2 +0 -0
  16. data/app/assets/fonts/spina/Metropolis-RegularItalic.woff2 +0 -0
  17. data/app/assets/fonts/spina/Metropolis-SemiBold.woff2 +0 -0
  18. data/app/assets/fonts/spina/Metropolis-SemiBoldItalic.woff2 +0 -0
  19. data/app/assets/fonts/spina/Metropolis-Thin.woff2 +0 -0
  20. data/app/assets/fonts/spina/Metropolis-ThinItalic.woff2 +0 -0
  21. data/app/assets/fonts/spina/ics_spina.eot +0 -0
  22. data/app/assets/fonts/spina/ics_spina.svg +285 -267
  23. data/app/assets/fonts/spina/ics_spina.ttf +0 -0
  24. data/app/assets/fonts/spina/ics_spina.woff +0 -0
  25. data/app/assets/fonts/spina/ics_spina.woff2 +0 -0
  26. data/app/assets/icons/spina/bold.svg +1 -1
  27. data/app/assets/icons/spina/code.svg +1 -1
  28. data/app/assets/icons/spina/image.svg +1 -10
  29. data/app/assets/icons/spina/indent.svg +1 -0
  30. data/app/assets/icons/spina/italic.svg +1 -1
  31. data/app/assets/icons/spina/link.svg +1 -1
  32. data/app/assets/icons/spina/list-ol.svg +1 -0
  33. data/app/assets/icons/spina/list.svg +1 -0
  34. data/app/assets/icons/spina/outdent.svg +1 -0
  35. data/app/assets/icons/spina/preview/ics_spina-preview.html +121 -1
  36. data/app/assets/icons/spina/quote-right.svg +1 -0
  37. data/app/assets/icons/spina/redo.svg +1 -0
  38. data/app/assets/icons/spina/strikethrough.svg +1 -0
  39. data/app/assets/icons/spina/undo.svg +1 -0
  40. data/app/assets/images/spina/favicon.png +0 -0
  41. data/app/assets/javascripts/spina/admin/application.js +1 -2
  42. data/app/assets/javascripts/spina/admin/controllers/attachment_picker_controller.js +15 -0
  43. data/app/assets/javascripts/spina/admin/controllers/image_form_controller.js +5 -4
  44. data/app/assets/javascripts/spina/admin/controllers/infinite_scroll_controller.js +20 -22
  45. data/app/assets/javascripts/spina/admin/controllers/media_picker_controller.js +171 -0
  46. data/app/assets/javascripts/spina/admin/controllers/modal_controller.js +18 -0
  47. data/app/assets/javascripts/spina/admin/controllers/repeater_form_controller.js +38 -0
  48. data/app/assets/javascripts/spina/admin/media_gallery.coffee +0 -3
  49. data/app/assets/javascripts/spina/admin/notifications.coffee +1 -1
  50. data/app/assets/javascripts/spina/admin/pages.coffee.erb +3 -20
  51. data/app/assets/javascripts/spina/admin/scaffold.coffee +0 -3
  52. data/app/assets/javascripts/spina/admin/trix.coffee.erb +14 -18
  53. data/app/assets/stylesheets/spina.sass +10 -10
  54. data/app/assets/stylesheets/spina/_buttons.sass +58 -32
  55. data/app/assets/stylesheets/spina/_configuration.sass.erb +2 -2
  56. data/app/assets/stylesheets/spina/_fonts.sass +32 -0
  57. data/app/assets/stylesheets/spina/_forms.sass +65 -76
  58. data/app/assets/stylesheets/spina/_gallery.sass +22 -4
  59. data/app/assets/stylesheets/spina/_ics_spina.scss +8 -0
  60. data/app/assets/stylesheets/spina/_media_picker.sass +133 -0
  61. data/app/assets/stylesheets/spina/_modal.sass +35 -2
  62. data/app/assets/stylesheets/spina/_notifications.sass +20 -14
  63. data/app/assets/stylesheets/spina/_pages.sass +131 -0
  64. data/app/assets/stylesheets/spina/_sortable_lists.sass +14 -8
  65. data/app/assets/stylesheets/spina/_tables.sass +7 -4
  66. data/app/assets/stylesheets/spina/_trix_custom.sass +15 -28
  67. data/app/controllers/concerns/spina/frontend.rb +9 -0
  68. data/app/controllers/spina/admin/accounts_controller.rb +9 -13
  69. data/app/controllers/spina/admin/attachments_controller.rb +0 -22
  70. data/app/controllers/spina/admin/images_controller.rb +1 -1
  71. data/app/controllers/spina/admin/media_folders_controller.rb +10 -0
  72. data/app/controllers/spina/admin/media_picker_controller.rb +18 -19
  73. data/app/controllers/spina/admin/pages_controller.rb +3 -7
  74. data/app/controllers/spina/admin/resources_controller.rb +9 -4
  75. data/app/controllers/spina/application_controller.rb +1 -1
  76. data/app/helpers/spina/admin/pages_helper.rb +22 -20
  77. data/app/helpers/spina/{files_helper.rb → attachments_helper.rb} +1 -1
  78. data/app/helpers/spina/images_helper.rb +14 -0
  79. data/app/helpers/spina/pages_helper.rb +23 -4
  80. data/app/models/concerns/spina/partable.rb +19 -7
  81. data/app/models/concerns/spina/translated_content.rb +19 -0
  82. data/app/models/spina/account.rb +3 -10
  83. data/app/models/spina/attachment.rb +0 -4
  84. data/app/models/spina/current.rb +1 -0
  85. data/app/models/spina/image.rb +0 -4
  86. data/app/models/spina/page.rb +19 -20
  87. data/app/models/spina/parts/attachment.rb +17 -0
  88. data/app/models/spina/parts/base.rb +12 -0
  89. data/app/models/spina/parts/image.rb +30 -0
  90. data/app/models/spina/parts/image_collection.rb +23 -0
  91. data/app/models/spina/parts/line.rb +7 -0
  92. data/app/models/spina/parts/option.rb +13 -0
  93. data/app/models/spina/parts/repeater.rb +10 -0
  94. data/app/models/spina/parts/repeater_content.rb +15 -0
  95. data/app/models/spina/parts/text.rb +7 -0
  96. data/app/models/spina/resource.rb +4 -12
  97. data/app/presenters/spina/content_presenter.rb +58 -0
  98. data/app/presenters/spina/menu_presenter.rb +2 -1
  99. data/app/views/layouts/spina/admin/admin.html.haml +3 -4
  100. data/app/views/layouts/spina/admin/pages.html.haml +5 -4
  101. data/app/views/spina/admin/accounts/_form.html.haml +13 -7
  102. data/app/views/spina/admin/accounts/analytics.html.haml +5 -3
  103. data/app/views/spina/admin/accounts/style.html.haml +26 -21
  104. data/app/views/spina/admin/images/index.html.haml +7 -5
  105. data/app/views/spina/admin/media_folders/_form.html.haml +5 -2
  106. data/app/views/spina/admin/media_folders/edit.js.erb +1 -0
  107. data/app/views/spina/admin/media_folders/show.html.haml +2 -1
  108. data/app/views/spina/admin/media_picker/_image.html.haml +3 -0
  109. data/app/views/spina/admin/media_picker/_media_picker.html.haml +32 -0
  110. data/app/views/spina/admin/media_picker/_media_picker_grid.html.haml +25 -0
  111. data/app/views/spina/admin/media_picker/infinite_scroll.js.erb +4 -4
  112. data/app/views/spina/admin/media_picker/select.js.erb +2 -0
  113. data/app/views/spina/admin/media_picker/show.html.haml +1 -0
  114. data/app/views/spina/admin/media_picker/show.js.erb +1 -1
  115. data/app/views/spina/admin/pages/_form.html.haml +10 -8
  116. data/app/views/spina/admin/pages/_form_advanced.html.haml +19 -17
  117. data/app/views/spina/admin/pages/_form_page_content.html.haml +14 -13
  118. data/app/views/spina/admin/pages/_form_page_seo.html.haml +15 -4
  119. data/app/views/spina/admin/pages/_page.html.haml +5 -3
  120. data/app/views/spina/admin/pages/_page_nested_list.html.haml +2 -3
  121. data/app/views/spina/admin/pages/index.html.haml +5 -4
  122. data/app/views/spina/admin/parts/attachments/_form.html.haml +6 -0
  123. data/app/views/spina/admin/parts/image_collections/_fields.html.haml +7 -0
  124. data/app/views/spina/admin/parts/image_collections/_form.html.haml +12 -0
  125. data/app/views/spina/admin/parts/images/_form.html.haml +18 -0
  126. data/app/views/spina/admin/parts/lines/_form.html.haml +2 -0
  127. data/app/views/spina/admin/parts/options/_form.html.haml +3 -0
  128. data/app/views/spina/admin/parts/repeaters/_fields.html.haml +15 -0
  129. data/app/views/spina/admin/parts/repeaters/_form.html.haml +18 -0
  130. data/app/views/spina/admin/parts/texts/_form.html.haml +6 -0
  131. data/app/views/spina/admin/resources/edit.html.haml +28 -12
  132. data/app/views/spina/admin/resources/show.html.haml +6 -3
  133. data/app/views/spina/admin/shared/_notifications.html.haml +4 -4
  134. data/config/locales/TH.yml +220 -205
  135. data/config/locales/bg.yml +219 -211
  136. data/config/locales/de.yml +218 -190
  137. data/config/locales/en.yml +218 -208
  138. data/config/locales/es.yml +219 -206
  139. data/config/locales/fr.yml +219 -190
  140. data/config/locales/id.yml +219 -189
  141. data/config/locales/it.yml +225 -152
  142. data/config/locales/nl.yml +220 -197
  143. data/config/locales/pl.yml +218 -185
  144. data/config/locales/pt-BR.yml +218 -205
  145. data/config/locales/ro.yml +258 -225
  146. data/config/locales/ru.yml +231 -171
  147. data/config/locales/sv.yml +218 -183
  148. data/config/locales/tr.yml +224 -151
  149. data/config/locales/zh-CN.yml +225 -175
  150. data/db/migrate/11_create_spina_resources.rb +0 -2
  151. data/db/migrate/12_add_url_title_to_spina_page_translations.rb +5 -0
  152. data/db/migrate/13_add_json_attributes_to_spina_accounts.rb +5 -0
  153. data/db/migrate/14_add_json_attributes_to_spina_pages.rb +5 -0
  154. data/db/migrate/15_add_slug_to_spina_resources.rb +5 -0
  155. data/lib/generators/spina/templates/app/views/demo/pages/demo.html.haml +13 -21
  156. data/lib/generators/spina/templates/app/views/demo/pages/homepage.html.haml +1 -1
  157. data/lib/generators/spina/templates/config/initializers/themes/default.rb +4 -4
  158. data/lib/generators/spina/templates/config/initializers/themes/demo.rb +32 -44
  159. data/lib/spina.rb +2 -0
  160. data/lib/spina/attr_json_spina_parts_model.rb +29 -0
  161. data/lib/spina/engine.rb +13 -3
  162. data/lib/spina/part.rb +19 -0
  163. data/lib/spina/theme.rb +1 -1
  164. data/lib/spina/version.rb +1 -1
  165. data/vendor/assets/javascripts/spina/sortable.js +2 -2
  166. metadata +71 -45
  167. data/app/assets/javascripts/spina/admin/account.coffee +0 -16
  168. data/app/models/concerns/spina/image_collectable.rb +0 -23
  169. data/app/models/concerns/spina/optionable.rb +0 -12
  170. data/app/models/concerns/spina/part.rb +0 -38
  171. data/app/models/spina/attachment_collection.rb +0 -20
  172. data/app/models/spina/image_collection.rb +0 -23
  173. data/app/models/spina/image_collections_image.rb +0 -6
  174. data/app/models/spina/layout_part.rb +0 -22
  175. data/app/models/spina/line.rb +0 -10
  176. data/app/models/spina/option.rb +0 -17
  177. data/app/models/spina/page_part.rb +0 -22
  178. data/app/models/spina/structure.rb +0 -14
  179. data/app/models/spina/structure_item.rb +0 -22
  180. data/app/models/spina/structure_part.rb +0 -20
  181. data/app/models/spina/text.rb +0 -10
  182. data/app/views/dummy/show.html.haml +0 -1
  183. data/app/views/spina/admin/attachments/_attachment_collection.html.haml +0 -2
  184. data/app/views/spina/admin/attachments/_select.html.haml +0 -17
  185. data/app/views/spina/admin/attachments/_select_collection.html.haml +0 -18
  186. data/app/views/spina/admin/attachments/insert.js.erb +0 -5
  187. data/app/views/spina/admin/attachments/insert_collection.js.coffee +0 -7
  188. data/app/views/spina/admin/attachments/select.js.erb +0 -2
  189. data/app/views/spina/admin/attachments/select_collection.js.erb +0 -2
  190. data/app/views/spina/admin/image_collections/_image_collection.html.haml +0 -5
  191. data/app/views/spina/admin/layout_partables/lines/_form.html.haml +0 -2
  192. data/app/views/spina/admin/partables/attachment_collections/_form.html.haml +0 -14
  193. data/app/views/spina/admin/partables/attachments/_form.html.haml +0 -13
  194. data/app/views/spina/admin/partables/image_collections/_form.html.haml +0 -16
  195. data/app/views/spina/admin/partables/images/_form.html.haml +0 -21
  196. data/app/views/spina/admin/partables/lines/_form.html.haml +0 -5
  197. data/app/views/spina/admin/partables/options/_form.html.haml +0 -7
  198. data/app/views/spina/admin/partables/photo_collections/_form.html.haml +0 -4
  199. data/app/views/spina/admin/partables/photos/_form.html.haml +0 -4
  200. data/app/views/spina/admin/partables/structures/_form.html.haml +0 -21
  201. data/app/views/spina/admin/partables/texts/_form.html.haml +0 -8
  202. data/app/views/spina/admin/structure_items/_fields.html.haml +0 -15
  203. data/app/views/spina/admin/structure_partables/attachment_collections/_form.html.haml +0 -14
  204. data/app/views/spina/admin/structure_partables/attachments/_form.html.haml +0 -13
@@ -0,0 +1,19 @@
1
+ module Spina
2
+ module TranslatedContent
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+
7
+ # Store each locale's content in [locale]_content as an array of parts
8
+ Spina.config.locales.each do |locale|
9
+ attr_json "#{locale}_content".to_sym, AttrJson::Type::SpinaPartsModel.new, array: true, default: -> { [] }
10
+ attr_json_accepts_nested_attributes_for "#{locale}_content".to_sym
11
+ end
12
+
13
+ def find_part(name)
14
+ send("#{I18n.locale}_content").find{|part| part.name.to_s == name.to_s}
15
+ end
16
+
17
+ end
18
+ end
19
+ end
@@ -1,25 +1,18 @@
1
1
  module Spina
2
2
  class Account < ApplicationRecord
3
+ include AttrJson::Record
4
+ include AttrJson::NestedAttributes
3
5
  include Partable
6
+ include TranslatedContent
4
7
 
5
8
  serialize :preferences
6
9
 
7
- has_many :layout_parts, dependent: :destroy
8
- accepts_nested_attributes_for :layout_parts, allow_destroy: true
9
-
10
- alias_attribute :layout_part, :part
11
- alias_attribute :parts, :layout_parts
12
-
13
10
  after_save :bootstrap_website
14
11
 
15
12
  def to_s
16
13
  name
17
14
  end
18
15
 
19
- def content(layout_part)
20
- layout_parts.find_by(name: layout_part).try(:content)
21
- end
22
-
23
16
  def self.serialized_attr_accessor(*args)
24
17
  args.each do |method_name|
25
18
  define_method method_name do
@@ -2,10 +2,6 @@ module Spina
2
2
  class Attachment < ApplicationRecord
3
3
  has_one_attached :file
4
4
 
5
- has_one :page_part, as: :page_partable
6
- has_many :structure_parts, as: :structure_partable
7
- has_and_belongs_to_many :attachment_collections, join_table: 'spina_attachment_collections_attachments'
8
-
9
5
  attr_accessor :_destroy
10
6
 
11
7
  scope :sorted, -> { order('file ASC') }
@@ -1,5 +1,6 @@
1
1
  module Spina
2
2
  class Current < ActiveSupport::CurrentAttributes
3
3
  attribute :page
4
+ attribute :account
4
5
  end
5
6
  end
@@ -4,11 +4,7 @@ module Spina
4
4
 
5
5
  has_one_attached :file
6
6
 
7
- has_many :page_parts, as: :page_partable
8
- has_many :structure_parts, as: :structure_partable
9
-
10
7
  scope :sorted, -> { order('created_at DESC') }
11
- scope :sorted_by_image_collection, -> { order('position') }
12
8
 
13
9
  def name
14
10
  file.try(:filename).to_s
@@ -1,16 +1,14 @@
1
1
  module Spina
2
2
  class Page < ApplicationRecord
3
3
  extend Mobility
4
+ include AttrJson::Record
5
+ include AttrJson::NestedAttributes
4
6
  include Partable
7
+ include TranslatedContent
5
8
 
6
9
  # Stores the old path when generating a new materialized_path
7
10
  attr_accessor :old_path
8
11
 
9
- # Page contains multiple parts called PageParts
10
- has_many :page_parts, dependent: :destroy, inverse_of: :page
11
- alias_attribute :parts, :page_parts
12
- accepts_nested_attributes_for :page_parts, allow_destroy: true
13
-
14
12
  # Orphaned pages are adopted by parent pages if available, otherwise become root
15
13
  has_ancestry orphan_strategy: :adopt
16
14
 
@@ -28,10 +26,12 @@ module Spina
28
26
  scope :live, -> { active.where(draft: false) }
29
27
  scope :in_menu, -> { where(show_in_menu: true) }
30
28
 
29
+ # Copy resource from parent
30
+ before_save :set_resource_from_parent, if: -> { parent.present? }
31
+
31
32
  # Save children to update all materialized_paths
32
33
  after_save :save_children
33
34
  after_save :touch_navigations
34
- after_save -> { page_parts.each(&:save) }
35
35
 
36
36
  # Create a 301 redirect if materialized_path changed
37
37
  after_save :rewrite_rule
@@ -41,7 +41,7 @@ module Spina
41
41
 
42
42
  translates :title, fallbacks: true
43
43
  translates :description, :materialized_path
44
- translates :menu_title, :seo_title, default: -> { title }
44
+ translates :menu_title, :seo_title, :url_title, default: -> { title }
45
45
 
46
46
  def to_s
47
47
  name
@@ -51,8 +51,8 @@ module Spina
51
51
  id
52
52
  end
53
53
 
54
- def url_title
55
- title.try(:parameterize)
54
+ def slug
55
+ url_title&.parameterize
56
56
  end
57
57
 
58
58
  def custom_page?
@@ -91,12 +91,12 @@ module Spina
91
91
  theme.view_templates.find { |template| template[:name] == view_template_name }
92
92
  end
93
93
 
94
- def view_template_page_parts(theme)
95
- theme.page_parts.select { |page_part| page_part[:name].in? view_template_config(theme)[:page_parts] }
96
- end
97
-
98
94
  private
99
95
 
96
+ def set_resource_from_parent
97
+ self.resource_id = parent.resource_id
98
+ end
99
+
100
100
  def touch_navigations
101
101
  navigations.update_all(updated_at: Time.zone.now)
102
102
  end
@@ -106,19 +106,18 @@ module Spina
106
106
  end
107
107
 
108
108
  def localized_materialized_path
109
- if I18n.locale == I18n.default_locale
109
+ if Mobility.locale == I18n.default_locale
110
110
  generate_materialized_path.prepend('/')
111
111
  else
112
- generate_materialized_path.prepend("/#{I18n.locale}/").gsub(/\/\z/, "")
112
+ generate_materialized_path.prepend("/#{Mobility.locale}/").gsub(/\/\z/, "")
113
113
  end
114
114
  end
115
115
 
116
116
  def generate_materialized_path
117
- if root?
118
- name == 'homepage' ? '' : "#{url_title}"
119
- else
120
- ancestors.collect(&:url_title).append(url_title).join('/')
121
- end
117
+ path_fragments = [resource&.slug]
118
+ path_fragments.append *ancestors.collect(&:slug)
119
+ path_fragments.append(slug) unless name == 'homepage'
120
+ path_fragments.compact.map(&:parameterize).join('/')
122
121
  end
123
122
 
124
123
  end
@@ -0,0 +1,17 @@
1
+ module Spina
2
+ module Parts
3
+ class Attachment < Base
4
+ attr_json :attachment_id, :integer, default: nil
5
+ attr_json :signed_blob_id, :string, default: nil
6
+ attr_json :filename, :string, default: ""
7
+
8
+ def content
9
+ self
10
+ end
11
+
12
+ def present?
13
+ signed_blob_id.present?
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,12 @@
1
+ module Spina
2
+ module Parts
3
+ class Base
4
+ include AttrJson::Model
5
+
6
+ attr_json_config(unknown_key: :strip)
7
+
8
+ attr_json :title, :string
9
+ attr_json :name, :string
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,30 @@
1
+ module Spina
2
+ module Parts
3
+ class Image < Base
4
+ attr_json :image_id, :integer, default: nil
5
+ attr_json :signed_blob_id, :string, default: nil
6
+ attr_json :alt, :string, default: ""
7
+ attr_json :filename, :string, default: ""
8
+
9
+ def to_s
10
+ alt.presence || filename.presence || Spina::Image.model_name.human
11
+ end
12
+
13
+ def content
14
+ self
15
+ end
16
+
17
+ def svg?
18
+ filename =~ /\.svg\z/
19
+ end
20
+
21
+ def spina_image
22
+ Spina::Image.find_by(id: image_id)
23
+ end
24
+
25
+ def present?
26
+ signed_blob_id.present?
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,23 @@
1
+ module Spina
2
+ module Parts
3
+ class ImageCollection < Base
4
+ include AttrJson::NestedAttributes
5
+
6
+ attr_json :images, Image.to_type, array: true
7
+ attr_json_accepts_nested_attributes_for :images
8
+
9
+ def to_s
10
+ Spina::Parts::ImageCollection.model_name.human
11
+ end
12
+
13
+ def content
14
+ (images || [])
15
+ end
16
+
17
+ def image_ids
18
+ content.map(&:image_id)
19
+ end
20
+
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ module Spina
2
+ module Parts
3
+ class Line < Base
4
+ attr_json :content, :string, default: ""
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,13 @@
1
+ module Spina
2
+ module Parts
3
+ class Option < Base
4
+ attr_json :value, :string, default: ""
5
+
6
+ attr_accessor :options
7
+
8
+ def content
9
+ value
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ module Spina
2
+ module Parts
3
+ class Repeater < Base
4
+ include AttrJson::NestedAttributes
5
+
6
+ attr_json :content, RepeaterContent.to_type, array: true
7
+ attr_json_accepts_nested_attributes_for :content
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module Spina
2
+ module Parts
3
+ class RepeaterContent < Base
4
+ include Partable
5
+ include AttrJson::NestedAttributes
6
+
7
+ attr_json :parts, AttrJson::Type::SpinaPartsModel.new, array: true
8
+ attr_json_accepts_nested_attributes_for :parts
9
+
10
+ def find_part(name)
11
+ (parts || []).find{|part| part.name.to_s == name.to_s}
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,7 @@
1
+ module Spina
2
+ module Parts
3
+ class Text < Base
4
+ attr_json :content, :string, default: ""
5
+ end
6
+ end
7
+ end
@@ -1,10 +1,10 @@
1
1
  module Spina
2
2
  class Resource < ApplicationRecord
3
- has_many :pages, dependent: :restrict_with_exception
3
+ extend Mobility
4
4
 
5
- belongs_to :parent_page, class_name: "Spina::Page", optional: true
5
+ has_many :pages, dependent: :restrict_with_exception
6
6
 
7
- after_save :scope_pages_to_parent_page
7
+ translates :slug, backend: :jsonb
8
8
 
9
9
  def pages
10
10
  case order_by
@@ -14,14 +14,6 @@ module Spina
14
14
  super.order(created_at: :desc)
15
15
  end
16
16
  end
17
-
18
- private
19
-
20
- def scope_pages_to_parent_page
21
- pages.roots.each do |root_page|
22
- root_page.update(parent: parent_page)
23
- end
24
- end
25
-
17
+
26
18
  end
27
19
  end
@@ -0,0 +1,58 @@
1
+ module Spina
2
+ class ContentPresenter
3
+ attr_reader :view_context, :container
4
+
5
+ def initialize(view_context, container)
6
+ @view_context = view_context || Spina::Current.page&.view_context
7
+ @container = container
8
+ end
9
+
10
+ def text(name)
11
+ part = find_part(name)
12
+ part&.content.to_s
13
+ end
14
+
15
+ def html(name)
16
+ html = find_part(name)&.content
17
+ ActiveSupport::SafeBuffer.new(html.to_s)
18
+ end
19
+
20
+ def image_tag(image, variant_options = {}, options = {})
21
+ image = find_part(image) unless image.is_a? Spina::Parts::Image
22
+ image_tag_options = {alt: image&.alt}
23
+ view_context.image_tag main_app_image_url(image, variant_options), options.merge(image_tag_options) if image.present?
24
+ end
25
+
26
+ def image_url(image, variant_options = {})
27
+ image = find_part(image) unless image.is_a? Spina::Parts::Image
28
+ main_app_image_url(image, variant_options) if image.present?
29
+ end
30
+
31
+ def attachment_url(attachment)
32
+ attachment = find_part(attachment) unless attachment.is_a? Spina::Parts::Attachment
33
+ rails_service_blob_url(attachment)
34
+ end
35
+
36
+ private
37
+
38
+ def main_app_image_url(image, variant_options = {})
39
+ # SVG's can't have variants,
40
+ # Render rails_service_blob_url directly instead
41
+ return rails_service_blob_url(image) if image.svg?
42
+
43
+ # Other images (like PNG & JPG) can have variants
44
+ variant_key = ActiveStorage::Variation.encode(variant_options)
45
+ view_context.main_app.rails_blob_representation_url(image.signed_blob_id, variant_key, image.filename.presence || "image")
46
+ end
47
+
48
+ def rails_service_blob_url(file)
49
+ return if file.blank?
50
+ view_context.main_app.rails_service_blob_url(file.signed_blob_id, filename: file.filename.presence || "file")
51
+ end
52
+
53
+ def find_part(name)
54
+ container.find_part(name)
55
+ end
56
+
57
+ end
58
+ end
@@ -50,6 +50,7 @@ module Spina
50
50
  end
51
51
 
52
52
  def render_item(item)
53
+ return nil unless item.materialized_path
53
54
  children = scoped_collection(item.children)
54
55
 
55
56
  content_tag(list_item_tag, class: list_item_css, data: {page_id: item.page_id, draft: (true if item.draft?) }) do
@@ -71,4 +72,4 @@ module Spina
71
72
  end
72
73
 
73
74
  end
74
- end
75
+ end
@@ -6,7 +6,9 @@
6
6
  = csrf_meta_tags
7
7
  %meta{name: 'turbolinks-cache-control', content: 'no-preview'}
8
8
 
9
- %title Spina
9
+ %link{rel: 'icon', href: image_url("spina/favicon.png")}
10
+
11
+ %title Spina CMS
10
12
 
11
13
  / Stylesheet
12
14
  = stylesheet_link_tag 'spina/admin/application', data: {turbolinks_track: true}
@@ -33,6 +35,3 @@
33
35
  = render 'spina/admin/shared/notifications'
34
36
 
35
37
  = content_for?(:application) ? yield(:application) : yield
36
-
37
- = link_to 'http://www.spinacms.com', class: 'spina-logo', target: :blank do
38
- = image_tag('spina/spina.svg', width: 32, height: 24)