macron-cms 3.0.0 → 5.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +338 -25
- data/app/assets/stylesheets/macron/cms/application.css +1 -1
- data/app/controllers/concerns/macron/cms/api_serialization.rb +79 -0
- data/app/controllers/concerns/macron/cms/slug_redirectable.rb +27 -0
- data/app/controllers/macron/cms/api/v1/article_contents_controller.rb +221 -0
- data/app/controllers/macron/cms/api/v1/articles_controller.rb +140 -66
- data/app/controllers/macron/cms/api/v1/content_types_controller.rb +3 -1
- data/app/controllers/macron/cms/article_contents_controller.rb +44 -10
- data/app/controllers/macron/cms/articles_controller.rb +4 -3
- data/app/controllers/macron/cms/content_types_controller.rb +2 -0
- data/app/controllers/macron/cms/dashboard_controller.rb +1 -1
- data/app/helpers/macron/cms/content_helper.rb +1 -1
- data/app/helpers/macron/cms/fields_helper.rb +14 -0
- data/app/models/macron/cms/article.rb +45 -15
- data/app/models/macron/cms/article_content.rb +24 -0
- data/app/models/macron/cms/content.rb +27 -0
- data/app/services/macron/cms/inline_asset_attacher.rb +70 -0
- data/app/services/macron/cms/remote_asset_attacher.rb +16 -6
- data/app/views/macron/cms/articles/_content_blocks_section.html.erb +494 -199
- data/app/views/macron/cms/articles/_form.html.erb +10 -2
- data/app/views/macron/cms/articles/_table.html.erb +3 -3
- data/app/views/macron/cms/articles/show.html.erb +3 -1
- data/app/views/macron/cms/content_types/index.html.erb +30 -0
- data/app/views/macron/cms/content_types/show.html.erb +34 -0
- data/config/routes.rb +12 -1
- data/db/migrate/20261029000001_add_convertible_to_to_macron_cms_contents.rb +5 -0
- data/db/migrate/20261029120001_add_featured_image_to_macron_cms_contents.rb +5 -0
- data/db/migrate/20261029120002_add_featured_image_blob_to_macron_cms_articles.rb +8 -0
- data/db/migrate/20261029140000_create_friendly_id_slugs.rb +26 -0
- data/db/migrate/20261029150000_remove_name_from_macron_cms_articles.rb +6 -0
- data/db/migrate/20261029160000_add_published_at_to_macron_cms_articles.rb +14 -0
- data/db/seeds.rb +3 -2
- data/lib/macron/cms/version.rb +1 -1
- data/lib/tasks/macron/cms_tasks.rake +6 -0
- metadata +11 -1
|
@@ -28,13 +28,21 @@
|
|
|
28
28
|
</div>
|
|
29
29
|
|
|
30
30
|
<div>
|
|
31
|
-
<%= form.label :
|
|
31
|
+
<%= form.label :slug, "Identifier Name", class: "block text-sm font-semibold text-zinc-900" %>
|
|
32
32
|
<div class="mt-1.5">
|
|
33
|
-
<%= form.text_field :
|
|
33
|
+
<%= form.text_field :slug, placeholder: "Leave blank to generate from title", class: "block w-full rounded-lg border border-zinc-300 px-3.5 py-2 text-zinc-900 shadow-xs placeholder:text-zinc-400 focus:outline-none focus:border-zinc-900 focus:ring-1 focus:ring-zinc-900 text-sm font-mono" %>
|
|
34
34
|
</div>
|
|
35
35
|
<p class="mt-1 text-xs text-zinc-500">Optional. Unique identifier used by FriendlyId to generate clean URLs (derived from title if left blank).</p>
|
|
36
36
|
</div>
|
|
37
37
|
|
|
38
|
+
<div>
|
|
39
|
+
<%= form.label :published_at, "Published Date & Time", class: "block text-sm font-semibold text-zinc-900" %>
|
|
40
|
+
<div class="mt-1.5">
|
|
41
|
+
<%= form.datetime_local_field :published_at, value: (article.published_at || Time.current).strftime("%Y-%m-%dT%H:%M"), class: "block w-full rounded-lg border border-zinc-300 px-3.5 py-2 text-zinc-900 shadow-xs placeholder:text-zinc-400 focus:outline-none focus:border-zinc-900 focus:ring-1 focus:ring-zinc-900 text-sm" %>
|
|
42
|
+
</div>
|
|
43
|
+
<p class="mt-1 text-xs text-zinc-500">Controls article sort order across the site and public publication date.</p>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
38
46
|
<div class="pt-6 border-t border-zinc-200 space-y-4">
|
|
39
47
|
<div>
|
|
40
48
|
<h3 class="text-sm font-semibold text-zinc-900">Styling & Background Settings</h3>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<thead class="bg-zinc-50 text-zinc-700 font-semibold text-xs uppercase tracking-wider">
|
|
6
6
|
<tr>
|
|
7
7
|
<th scope="col" class="px-6 py-3.5">Title</th>
|
|
8
|
-
<th scope="col" class="px-6 py-3.5">
|
|
8
|
+
<th scope="col" class="px-6 py-3.5">Published At</th>
|
|
9
9
|
<th scope="col" class="px-6 py-3.5 text-right">Actions</th>
|
|
10
10
|
</tr>
|
|
11
11
|
</thead>
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
<%= link_to article.title, article_path(article), class: "hover:underline" %>
|
|
17
17
|
</td>
|
|
18
18
|
<td class="px-6 py-4 text-zinc-500 text-xs whitespace-nowrap">
|
|
19
|
-
<%= article.created_at.strftime("%b %d, %Y") %>
|
|
19
|
+
<%= (article.published_at || article.created_at).strftime("%b %d, %Y %H:%M") %>
|
|
20
20
|
</td>
|
|
21
21
|
<td class="px-6 py-4 text-right text-xs font-medium whitespace-nowrap">
|
|
22
22
|
<div class="flex items-center justify-end gap-3 whitespace-nowrap">
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
<%= link_to "Show", article_path(article), class: "text-zinc-700 hover:text-zinc-900 hover:underline" %>
|
|
27
27
|
<%= link_to "Edit", edit_article_path(article), class: "text-zinc-700 hover:text-zinc-900 hover:underline" %>
|
|
28
28
|
<% delete_confirm = "Are you sure you want to delete \"#{article.title}\"?" %>
|
|
29
|
-
<%= button_to "Delete", article_path(article), method: :delete, form_class: "inline",
|
|
29
|
+
<%= button_to "Delete", article_path(article), method: :delete, form_class: "inline", data: { turbo_confirm: delete_confirm }, class: "text-rose-600 hover:text-rose-800 hover:underline cursor-pointer" %>
|
|
30
30
|
</div>
|
|
31
31
|
</td>
|
|
32
32
|
</tr>
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
</span>
|
|
14
14
|
</div>
|
|
15
15
|
<div class="text-xs text-zinc-500 space-y-0.5">
|
|
16
|
+
<p>Published: <%= (@article.published_at || @article.created_at).strftime("%B %d, %Y at %H:%M UTC") %></p>
|
|
16
17
|
<p>Created: <%= @article.created_at.strftime("%B %d, %Y at %H:%M UTC") %></p>
|
|
17
18
|
<p>Updated: <%= time_ago_in_words(@article.updated_at) %> ago</p>
|
|
18
19
|
</div>
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
<% end %>
|
|
38
39
|
|
|
39
40
|
<% delete_confirm = "Are you sure you want to delete \"#{@article.title}\"?" %>
|
|
40
|
-
<%= button_to article_path(@article), method: :delete,
|
|
41
|
+
<%= button_to article_path(@article), method: :delete, data: { turbo_confirm: delete_confirm }, class: "inline-flex items-center gap-1.5 rounded-lg border border-rose-200 bg-rose-50 px-3.5 py-2 text-sm font-semibold text-rose-700 hover:bg-rose-100 transition-colors cursor-pointer" do %>
|
|
41
42
|
<svg class="w-4 h-4 text-rose-500" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
|
|
42
43
|
<path stroke-linecap="round" stroke-linejoin="round" d="m14.74 9-.346 9m-4.788 0L9.26 9m9.968-3.21c.342.052.682.107 1.022.166m-1.022-.165L18.16 19.673a2.25 2.25 0 0 1-2.244 2.077H8.084a2.25 2.25 0 0 1-2.244-2.077L4.772 5.79m14.456 0a48.108 48.108 0 0 0-3.478-.397m-12 .562c.34-.059.68-.114 1.022-.165m0 0a48.11 48.11 0 0 1 3.478-.397m7.5 0v-.916c0-1.18-.91-2.164-2.09-2.201a51.964 51.964 0 0 0-3.32 0c-1.18.037-2.09 1.022-2.09 2.201v.916m7.5 0a48.667 48.667 0 0 0-7.5 0" />
|
|
43
44
|
</svg>
|
|
@@ -69,6 +70,7 @@
|
|
|
69
70
|
article: @article,
|
|
70
71
|
article_contents: @article_contents,
|
|
71
72
|
content_types: @content_types,
|
|
73
|
+
compact: (params[:view] == "compact"),
|
|
72
74
|
newly_added_id: nil,
|
|
73
75
|
updated_id: nil %>
|
|
74
76
|
</div>
|
|
@@ -23,6 +23,8 @@
|
|
|
23
23
|
<tr>
|
|
24
24
|
<th scope="col" class="px-6 py-3.5">Name</th>
|
|
25
25
|
<th scope="col" class="px-6 py-3.5">Fields Summary</th>
|
|
26
|
+
<th scope="col" class="px-6 py-3.5">Convertible To</th>
|
|
27
|
+
<th scope="col" class="px-6 py-3.5">Featured Image</th>
|
|
26
28
|
<th scope="col" class="px-6 py-3.5">Created At</th>
|
|
27
29
|
<th scope="col" class="px-6 py-3.5 text-right">Actions</th>
|
|
28
30
|
</tr>
|
|
@@ -58,6 +60,34 @@
|
|
|
58
60
|
<span class="text-zinc-600 italic">No fields defined</span>
|
|
59
61
|
<% end %>
|
|
60
62
|
</td>
|
|
63
|
+
<td class="px-6 py-4 text-zinc-600 text-xs">
|
|
64
|
+
<% convertible_names = content_type.normalized_convertible_to %>
|
|
65
|
+
<% if convertible_names.any? %>
|
|
66
|
+
<div class="flex flex-wrap gap-1.5">
|
|
67
|
+
<% convertible_names.each do |target_name| %>
|
|
68
|
+
<% target_ct = (@content_types_by_name || {})[target_name] %>
|
|
69
|
+
<% if target_ct %>
|
|
70
|
+
<%= link_to target_name, content_type_path(target_ct), class: "inline-flex items-center rounded-md bg-emerald-50 px-2 py-0.5 font-mono text-[11px] font-medium text-emerald-800 ring-1 ring-inset ring-emerald-200 hover:bg-emerald-100 transition-colors" %>
|
|
71
|
+
<% else %>
|
|
72
|
+
<span class="inline-flex items-center rounded-md bg-zinc-100 px-2 py-0.5 font-mono text-[11px] text-zinc-700 ring-1 ring-inset ring-zinc-200">
|
|
73
|
+
<%= target_name %>
|
|
74
|
+
</span>
|
|
75
|
+
<% end %>
|
|
76
|
+
<% end %>
|
|
77
|
+
</div>
|
|
78
|
+
<% else %>
|
|
79
|
+
<span class="text-zinc-400">—</span>
|
|
80
|
+
<% end %>
|
|
81
|
+
</td>
|
|
82
|
+
<td class="px-6 py-4 text-zinc-600 text-xs whitespace-nowrap">
|
|
83
|
+
<% if content_type.featured_image? %>
|
|
84
|
+
<span class="inline-flex items-center rounded-md bg-emerald-50 px-2 py-0.5 font-mono text-[11px] font-medium text-emerald-800 ring-1 ring-inset ring-emerald-200">
|
|
85
|
+
Yes
|
|
86
|
+
</span>
|
|
87
|
+
<% else %>
|
|
88
|
+
<span class="text-zinc-400">—</span>
|
|
89
|
+
<% end %>
|
|
90
|
+
</td>
|
|
61
91
|
<td class="px-6 py-4 text-zinc-500 text-xs whitespace-nowrap">
|
|
62
92
|
<%= content_type.created_at.strftime("%b %d, %Y") rescue "—" %>
|
|
63
93
|
</td>
|
|
@@ -57,6 +57,40 @@
|
|
|
57
57
|
<dt class="text-sm font-medium text-zinc-500">Field Count</dt>
|
|
58
58
|
<dd class="mt-1 text-sm text-zinc-900 sm:col-span-2 sm:mt-0"><%= field_list.count %></dd>
|
|
59
59
|
</div>
|
|
60
|
+
<div class="px-6 py-4 sm:grid sm:grid-cols-3 sm:gap-4">
|
|
61
|
+
<dt class="text-sm font-medium text-zinc-500">Convertible To</dt>
|
|
62
|
+
<dd class="mt-1 text-sm text-zinc-900 sm:col-span-2 sm:mt-0">
|
|
63
|
+
<% convertible_names = @content_type.normalized_convertible_to %>
|
|
64
|
+
<% if convertible_names.any? %>
|
|
65
|
+
<div class="flex flex-wrap gap-1.5">
|
|
66
|
+
<% convertible_names.each do |target_name| %>
|
|
67
|
+
<% target_ct = (@convertible_targets_by_name || {})[target_name] %>
|
|
68
|
+
<% if target_ct %>
|
|
69
|
+
<%= link_to target_name, content_type_path(target_ct), class: "inline-flex items-center rounded-md bg-emerald-50 px-2.5 py-0.5 text-xs font-mono font-medium text-emerald-800 ring-1 ring-inset ring-emerald-200 hover:bg-emerald-100 transition-colors" %>
|
|
70
|
+
<% else %>
|
|
71
|
+
<span class="inline-flex items-center rounded-md bg-zinc-100 px-2.5 py-0.5 text-xs font-mono text-zinc-700 ring-1 ring-inset ring-zinc-200">
|
|
72
|
+
<%= target_name %>
|
|
73
|
+
</span>
|
|
74
|
+
<% end %>
|
|
75
|
+
<% end %>
|
|
76
|
+
</div>
|
|
77
|
+
<% else %>
|
|
78
|
+
<span class="text-zinc-500 italic">None</span>
|
|
79
|
+
<% end %>
|
|
80
|
+
</dd>
|
|
81
|
+
</div>
|
|
82
|
+
<div class="px-6 py-4 sm:grid sm:grid-cols-3 sm:gap-4">
|
|
83
|
+
<dt class="text-sm font-medium text-zinc-500">Featured Image</dt>
|
|
84
|
+
<dd class="mt-1 text-sm text-zinc-900 sm:col-span-2 sm:mt-0">
|
|
85
|
+
<% if @content_type.featured_image? %>
|
|
86
|
+
<span class="inline-flex items-center rounded-md bg-emerald-50 px-2.5 py-0.5 text-xs font-mono font-medium text-emerald-800 ring-1 ring-inset ring-emerald-200">
|
|
87
|
+
Yes
|
|
88
|
+
</span>
|
|
89
|
+
<% else %>
|
|
90
|
+
<span class="text-zinc-500 italic">No</span>
|
|
91
|
+
<% end %>
|
|
92
|
+
</dd>
|
|
93
|
+
</div>
|
|
60
94
|
<div class="px-6 py-4 sm:grid sm:grid-cols-3 sm:gap-4">
|
|
61
95
|
<dt class="text-sm font-medium text-zinc-500">Created At</dt>
|
|
62
96
|
<dd class="mt-1 text-sm text-zinc-900 sm:col-span-2 sm:mt-0"><%= @content_type.created_at.to_fs(:long) rescue @content_type.created_at.to_s %></dd>
|
data/config/routes.rb
CHANGED
|
@@ -7,6 +7,7 @@ Macron::Cms::Engine.routes.draw do
|
|
|
7
7
|
resources :article_contents, only: %i[create update destroy] do
|
|
8
8
|
member do
|
|
9
9
|
patch :move
|
|
10
|
+
patch :convert
|
|
10
11
|
end
|
|
11
12
|
collection do
|
|
12
13
|
patch :reorder
|
|
@@ -18,7 +19,17 @@ Macron::Cms::Engine.routes.draw do
|
|
|
18
19
|
namespace :api do
|
|
19
20
|
namespace :v1 do
|
|
20
21
|
resources :content_types, only: %i[index]
|
|
21
|
-
resources :articles, only: %i[create show update]
|
|
22
|
+
resources :articles, only: %i[index create show update destroy] do
|
|
23
|
+
resources :content_blocks, controller: "article_contents", only: %i[create update destroy] do
|
|
24
|
+
member do
|
|
25
|
+
patch :move
|
|
26
|
+
patch :convert
|
|
27
|
+
end
|
|
28
|
+
collection do
|
|
29
|
+
patch :reorder
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
22
33
|
end
|
|
23
34
|
end
|
|
24
35
|
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class CreateFriendlyIdSlugs < ActiveRecord::Migration[8.0]
|
|
2
|
+
def change
|
|
3
|
+
create_table :friendly_id_slugs do |t|
|
|
4
|
+
t.string :slug, null: false
|
|
5
|
+
t.integer :sluggable_id, null: false
|
|
6
|
+
t.string :sluggable_type, limit: 50
|
|
7
|
+
t.string :scope
|
|
8
|
+
t.datetime :created_at
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
add_index :friendly_id_slugs, [ :sluggable_type, :sluggable_id ]
|
|
12
|
+
add_index :friendly_id_slugs, [ :slug, :sluggable_type ], length: { slug: 140, sluggable_type: 50 }
|
|
13
|
+
add_index :friendly_id_slugs, [ :slug, :sluggable_type, :scope ], length: { slug: 70, sluggable_type: 50, scope: 70 }, unique: true
|
|
14
|
+
|
|
15
|
+
reversible do |dir|
|
|
16
|
+
dir.up do
|
|
17
|
+
execute <<~SQL
|
|
18
|
+
INSERT INTO friendly_id_slugs (slug, sluggable_id, sluggable_type, created_at)
|
|
19
|
+
SELECT slug, id, 'Macron::Cms::Article', CURRENT_TIMESTAMP
|
|
20
|
+
FROM macron_cms_articles
|
|
21
|
+
WHERE slug IS NOT NULL AND slug <> '';
|
|
22
|
+
SQL
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
class AddPublishedAtToMacronCmsArticles < ActiveRecord::Migration[8.0]
|
|
2
|
+
def up
|
|
3
|
+
add_column :macron_cms_articles, :published_at, :datetime
|
|
4
|
+
add_index :macron_cms_articles, :published_at
|
|
5
|
+
|
|
6
|
+
Macron::Cms::Article.reset_column_information
|
|
7
|
+
execute("UPDATE macron_cms_articles SET published_at = created_at WHERE published_at IS NULL")
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def down
|
|
11
|
+
remove_index :macron_cms_articles, :published_at, if_exists: true
|
|
12
|
+
remove_column :macron_cms_articles, :published_at
|
|
13
|
+
end
|
|
14
|
+
end
|
data/db/seeds.rb
CHANGED
|
@@ -51,11 +51,12 @@ articles = [
|
|
|
51
51
|
}
|
|
52
52
|
]
|
|
53
53
|
|
|
54
|
-
articles.
|
|
55
|
-
article = Macron::Cms::Article.find_or_initialize_by(
|
|
54
|
+
articles.each_with_index do |data, index|
|
|
55
|
+
article = Macron::Cms::Article.find_or_initialize_by(slug: data[:title].parameterize)
|
|
56
56
|
article.title = data[:title]
|
|
57
57
|
article.meta_title = data[:meta_title]
|
|
58
58
|
article.meta_description = data[:meta_description]
|
|
59
|
+
article.published_at ||= (Time.current - (articles.size - index).days)
|
|
59
60
|
article.save!
|
|
60
61
|
end
|
|
61
62
|
|
data/lib/macron/cms/version.rb
CHANGED
|
@@ -24,9 +24,15 @@ namespace :macron do
|
|
|
24
24
|
content_type_name = File.basename(file, ".*")
|
|
25
25
|
data = YAML.safe_load_file(file, permitted_classes: [ Symbol ], aliases: true) || {}
|
|
26
26
|
fields = data["fields"] || data[:fields] || {}
|
|
27
|
+
raw_convertible = data["convertible_to"] || data[:convertible_to] || []
|
|
28
|
+
convertible_to = Array(raw_convertible).filter_map { |v| v.to_s.strip.presence }.uniq
|
|
29
|
+
raw_featured_image = data.key?("featured_image") ? data["featured_image"] : data[:featured_image]
|
|
30
|
+
featured_image = ActiveModel::Type::Boolean.new.cast(raw_featured_image) || false
|
|
27
31
|
|
|
28
32
|
content = Macron::Cms::Content.find_or_initialize_by(name: content_type_name)
|
|
29
33
|
content.fields = fields
|
|
34
|
+
content.convertible_to = convertible_to
|
|
35
|
+
content.featured_image = featured_image
|
|
30
36
|
content.save!
|
|
31
37
|
|
|
32
38
|
puts "Imported content type: #{content_type_name}"
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: macron-cms
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 5.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Leonid Medovyy
|
|
@@ -161,6 +161,9 @@ files:
|
|
|
161
161
|
- app/assets/stylesheets/macron/cms/katex.min.css
|
|
162
162
|
- app/assets/tailwind/macron/cms/application.css
|
|
163
163
|
- app/components/macron/cms/widget_component.rb
|
|
164
|
+
- app/controllers/concerns/macron/cms/api_serialization.rb
|
|
165
|
+
- app/controllers/concerns/macron/cms/slug_redirectable.rb
|
|
166
|
+
- app/controllers/macron/cms/api/v1/article_contents_controller.rb
|
|
164
167
|
- app/controllers/macron/cms/api/v1/articles_controller.rb
|
|
165
168
|
- app/controllers/macron/cms/api/v1/base_controller.rb
|
|
166
169
|
- app/controllers/macron/cms/api/v1/content_types_controller.rb
|
|
@@ -179,6 +182,7 @@ files:
|
|
|
179
182
|
- app/models/macron/cms/article.rb
|
|
180
183
|
- app/models/macron/cms/article_content.rb
|
|
181
184
|
- app/models/macron/cms/content.rb
|
|
185
|
+
- app/services/macron/cms/inline_asset_attacher.rb
|
|
182
186
|
- app/services/macron/cms/remote_asset_attacher.rb
|
|
183
187
|
- app/views/layouts/macron/cms/application.html.erb
|
|
184
188
|
- app/views/macron/cms/articles/_content_blocks_section.html.erb
|
|
@@ -210,6 +214,12 @@ files:
|
|
|
210
214
|
- db/migrate/20261028000006_move_payload_to_macron_cms_article_contents.rb
|
|
211
215
|
- db/migrate/20261028000007_add_background_fields_to_macron_cms_articles.rb
|
|
212
216
|
- db/migrate/20261028000008_add_text_color_to_macron_cms_articles.rb
|
|
217
|
+
- db/migrate/20261029000001_add_convertible_to_to_macron_cms_contents.rb
|
|
218
|
+
- db/migrate/20261029120001_add_featured_image_to_macron_cms_contents.rb
|
|
219
|
+
- db/migrate/20261029120002_add_featured_image_blob_to_macron_cms_articles.rb
|
|
220
|
+
- db/migrate/20261029140000_create_friendly_id_slugs.rb
|
|
221
|
+
- db/migrate/20261029150000_remove_name_from_macron_cms_articles.rb
|
|
222
|
+
- db/migrate/20261029160000_add_published_at_to_macron_cms_articles.rb
|
|
213
223
|
- db/seeds.rb
|
|
214
224
|
- lib/generators/macron/cms/content_type/content_type_generator.rb
|
|
215
225
|
- lib/macron/cms.rb
|