railspress-engine 0.1.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +67 -0
- data/Rakefile +10 -0
- data/app/assets/javascripts/railspress/admin.js +210 -0
- data/app/assets/stylesheets/actiontext.css +440 -0
- data/app/assets/stylesheets/railspress/admin.css +1199 -0
- data/app/assets/stylesheets/railspress/application.css +15 -0
- data/app/controllers/railspress/admin/base_controller.rb +38 -0
- data/app/controllers/railspress/admin/categories_controller.rb +53 -0
- data/app/controllers/railspress/admin/dashboard_controller.rb +12 -0
- data/app/controllers/railspress/admin/posts_controller.rb +71 -0
- data/app/controllers/railspress/admin/tags_controller.rb +50 -0
- data/app/controllers/railspress/application_controller.rb +4 -0
- data/app/helpers/railspress/application_helper.rb +4 -0
- data/app/jobs/railspress/application_job.rb +4 -0
- data/app/mailers/railspress/application_mailer.rb +6 -0
- data/app/models/railspress/application_record.rb +6 -0
- data/app/models/railspress/category.rb +18 -0
- data/app/models/railspress/post.rb +74 -0
- data/app/models/railspress/post_tag.rb +8 -0
- data/app/models/railspress/tag.rb +32 -0
- data/app/views/active_storage/blobs/_blob.html.erb +14 -0
- data/app/views/layouts/action_text/contents/_content.html.erb +3 -0
- data/app/views/layouts/railspress/admin.html.erb +41 -0
- data/app/views/layouts/railspress/application.html.erb +17 -0
- data/app/views/railspress/admin/categories/_form.html.erb +32 -0
- data/app/views/railspress/admin/categories/edit.html.erb +6 -0
- data/app/views/railspress/admin/categories/index.html.erb +42 -0
- data/app/views/railspress/admin/categories/new.html.erb +6 -0
- data/app/views/railspress/admin/dashboard/index.html.erb +45 -0
- data/app/views/railspress/admin/posts/_form.html.erb +129 -0
- data/app/views/railspress/admin/posts/edit.html.erb +2 -0
- data/app/views/railspress/admin/posts/index.html.erb +55 -0
- data/app/views/railspress/admin/posts/new.html.erb +2 -0
- data/app/views/railspress/admin/posts/show.html.erb +47 -0
- data/app/views/railspress/admin/shared/_flash.html.erb +5 -0
- data/app/views/railspress/admin/shared/_sidebar.html.erb +38 -0
- data/app/views/railspress/admin/tags/_form.html.erb +27 -0
- data/app/views/railspress/admin/tags/edit.html.erb +6 -0
- data/app/views/railspress/admin/tags/index.html.erb +42 -0
- data/app/views/railspress/admin/tags/new.html.erb +6 -0
- data/config/routes.rb +9 -0
- data/db/migrate/20241218000001_create_railspress_categories.rb +14 -0
- data/db/migrate/20241218000002_create_railspress_tags.rb +13 -0
- data/db/migrate/20241218000003_create_railspress_posts.rb +19 -0
- data/db/migrate/20241218000004_create_railspress_post_tags.rb +12 -0
- data/lib/generators/railspress/authors/authors_generator.rb +73 -0
- data/lib/generators/railspress/authors/templates/add_author_to_railspress_posts.rb.tt +8 -0
- data/lib/generators/railspress/authors/templates/railspress.rb.tt +31 -0
- data/lib/generators/railspress/install/install_generator.rb +144 -0
- data/lib/railspress/engine.rb +14 -0
- data/lib/railspress/version.rb +3 -0
- data/lib/railspress.rb +79 -0
- data/lib/tasks/railspress_tasks.rake +4 -0
- metadata +141 -0
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/base"
|
|
5
|
+
|
|
6
|
+
module Railspress
|
|
7
|
+
module Generators
|
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
|
9
|
+
source_root File.expand_path("templates", __dir__)
|
|
10
|
+
|
|
11
|
+
desc "Install RailsPress: copy migrations, mount engine, and configure JavaScript"
|
|
12
|
+
|
|
13
|
+
def copy_railspress_migrations
|
|
14
|
+
rake "railspress:install:migrations"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def copy_action_text_migrations
|
|
18
|
+
if action_text_migration_exists?
|
|
19
|
+
say_status :skip, "ActionText migrations already exist", :yellow
|
|
20
|
+
else
|
|
21
|
+
say_status :create, "ActionText migrations", :green
|
|
22
|
+
rake "railties:install:migrations FROM=action_text"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def copy_active_storage_migrations
|
|
27
|
+
if active_storage_migration_exists?
|
|
28
|
+
say_status :skip, "ActiveStorage migrations already exist", :yellow
|
|
29
|
+
else
|
|
30
|
+
say_status :create, "ActiveStorage migrations", :green
|
|
31
|
+
rake "railties:install:migrations FROM=active_storage"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def mount_engine
|
|
36
|
+
route_content = 'mount Railspress::Engine => "/railspress"'
|
|
37
|
+
|
|
38
|
+
if File.read(rails_route_file).include?("Railspress::Engine")
|
|
39
|
+
say_status :skip, "RailsPress engine already mounted", :yellow
|
|
40
|
+
else
|
|
41
|
+
route route_content
|
|
42
|
+
say_status :mounted, "RailsPress engine at /railspress", :green
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def configure_importmap
|
|
47
|
+
return unless importmap_available?
|
|
48
|
+
|
|
49
|
+
importmap_file = Rails.root.join("config", "importmap.rb")
|
|
50
|
+
importmap_content = File.read(importmap_file)
|
|
51
|
+
|
|
52
|
+
# Pin ActiveStorage (required for ActionText attachments)
|
|
53
|
+
unless importmap_content.include?("@rails/activestorage")
|
|
54
|
+
append_to_file importmap_file, <<~RUBY
|
|
55
|
+
|
|
56
|
+
# ActiveStorage for file uploads
|
|
57
|
+
pin "@rails/activestorage", to: "activestorage.esm.js"
|
|
58
|
+
RUBY
|
|
59
|
+
say_status :pinned, "@rails/activestorage in importmap", :green
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Pin Lexxy editor
|
|
63
|
+
if importmap_content.include?('"lexxy"')
|
|
64
|
+
say_status :skip, "Lexxy already pinned in importmap", :yellow
|
|
65
|
+
else
|
|
66
|
+
append_to_file importmap_file, <<~RUBY
|
|
67
|
+
|
|
68
|
+
# RailsPress rich text editor
|
|
69
|
+
pin "lexxy", to: "lexxy.js"
|
|
70
|
+
RUBY
|
|
71
|
+
say_status :pinned, "Lexxy in importmap", :green
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def configure_javascript
|
|
76
|
+
return unless importmap_available?
|
|
77
|
+
|
|
78
|
+
application_js = Rails.root.join("app", "javascript", "application.js")
|
|
79
|
+
return unless File.exist?(application_js)
|
|
80
|
+
|
|
81
|
+
js_content = File.read(application_js)
|
|
82
|
+
|
|
83
|
+
if js_content.include?('import "lexxy"')
|
|
84
|
+
say_status :skip, "Lexxy already imported in application.js", :yellow
|
|
85
|
+
else
|
|
86
|
+
append_to_file application_js, <<~JS
|
|
87
|
+
|
|
88
|
+
// RailsPress rich text editor
|
|
89
|
+
import "lexxy"
|
|
90
|
+
JS
|
|
91
|
+
say_status :added, "Lexxy import to application.js", :green
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def show_post_install_message
|
|
96
|
+
say ""
|
|
97
|
+
say "=" * 60, :green
|
|
98
|
+
say " RailsPress installed successfully!", :green
|
|
99
|
+
say "=" * 60, :green
|
|
100
|
+
say ""
|
|
101
|
+
say "Next steps:", :yellow
|
|
102
|
+
say ""
|
|
103
|
+
say " 1. Run migrations:"
|
|
104
|
+
say " $ rails db:migrate", :cyan
|
|
105
|
+
say ""
|
|
106
|
+
say " 2. Access the admin dashboard:"
|
|
107
|
+
say " http://localhost:3000/railspress/admin", :cyan
|
|
108
|
+
say ""
|
|
109
|
+
say " 3. (Optional) Change the mount path in config/routes.rb:"
|
|
110
|
+
say " mount Railspress::Engine => \"/blog\"", :cyan
|
|
111
|
+
say ""
|
|
112
|
+
say "JavaScript setup:", :yellow
|
|
113
|
+
say " The installer added Lexxy (rich text editor) to your importmap"
|
|
114
|
+
say " and application.js. If you use a custom JS entry point, add:"
|
|
115
|
+
say ""
|
|
116
|
+
say " import \"lexxy\"", :cyan
|
|
117
|
+
say ""
|
|
118
|
+
say "=" * 60, :green
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
private
|
|
122
|
+
|
|
123
|
+
def rails_route_file
|
|
124
|
+
Rails.root.join("config", "routes.rb")
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def migrations_dir
|
|
128
|
+
Rails.root.join("db", "migrate")
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def action_text_migration_exists?
|
|
132
|
+
Dir.glob(migrations_dir.join("*_create_action_text_tables*.rb")).any?
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
def active_storage_migration_exists?
|
|
136
|
+
Dir.glob(migrations_dir.join("*_create_active_storage_tables*.rb")).any?
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def importmap_available?
|
|
140
|
+
defined?(Importmap) && Rails.root.join("config", "importmap.rb").exist?
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
module Railspress
|
|
2
|
+
class Engine < ::Rails::Engine
|
|
3
|
+
isolate_namespace Railspress
|
|
4
|
+
|
|
5
|
+
# Register engine assets with the asset pipeline (Propshaft)
|
|
6
|
+
initializer "railspress.assets" do |app|
|
|
7
|
+
if app.config.respond_to?(:assets)
|
|
8
|
+
app.config.assets.paths << root.join("app", "assets", "stylesheets").to_s
|
|
9
|
+
app.config.assets.paths << root.join("app", "assets", "javascripts").to_s
|
|
10
|
+
app.config.assets.paths << root.join("app", "assets", "images").to_s
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
data/lib/railspress.rb
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
require "railspress/version"
|
|
2
|
+
require "railspress/engine"
|
|
3
|
+
require "lexxy"
|
|
4
|
+
|
|
5
|
+
module Railspress
|
|
6
|
+
class Configuration
|
|
7
|
+
attr_accessor :author_class_name,
|
|
8
|
+
:current_author_method,
|
|
9
|
+
:author_scope,
|
|
10
|
+
:author_display_method
|
|
11
|
+
|
|
12
|
+
attr_reader :authors_enabled, :header_images_enabled
|
|
13
|
+
|
|
14
|
+
def initialize
|
|
15
|
+
@authors_enabled = false
|
|
16
|
+
@header_images_enabled = false
|
|
17
|
+
@author_class_name = "User"
|
|
18
|
+
@current_author_method = :current_user
|
|
19
|
+
@author_scope = nil
|
|
20
|
+
@author_display_method = :name
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Declarative setter: config.enable_authors
|
|
24
|
+
def enable_authors
|
|
25
|
+
@authors_enabled = true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Declarative setter: config.enable_header_images
|
|
29
|
+
def enable_header_images
|
|
30
|
+
@header_images_enabled = true
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
class << self
|
|
35
|
+
def configuration
|
|
36
|
+
@configuration ||= Configuration.new
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def configure
|
|
40
|
+
yield(configuration)
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def reset_configuration!
|
|
44
|
+
@configuration = Configuration.new
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Convenience accessors
|
|
48
|
+
def authors_enabled?
|
|
49
|
+
configuration.authors_enabled
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def header_images_enabled?
|
|
53
|
+
configuration.header_images_enabled
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def author_class
|
|
57
|
+
configuration.author_class_name.constantize
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def available_authors
|
|
61
|
+
scope = configuration.author_scope
|
|
62
|
+
klass = author_class
|
|
63
|
+
|
|
64
|
+
case scope
|
|
65
|
+
when Symbol then klass.public_send(scope)
|
|
66
|
+
when Proc then scope.call(klass)
|
|
67
|
+
else klass.all
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def author_display_method
|
|
72
|
+
configuration.author_display_method
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def current_author_method
|
|
76
|
+
configuration.current_author_method
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: railspress-engine
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Avi Flombaum
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: rails
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '8.0'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '8.0'
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: lexxy
|
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
|
29
|
+
requirements:
|
|
30
|
+
- - "~>"
|
|
31
|
+
- !ruby/object:Gem::Version
|
|
32
|
+
version: 0.1.23.beta
|
|
33
|
+
type: :runtime
|
|
34
|
+
prerelease: false
|
|
35
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
36
|
+
requirements:
|
|
37
|
+
- - "~>"
|
|
38
|
+
- !ruby/object:Gem::Version
|
|
39
|
+
version: 0.1.23.beta
|
|
40
|
+
description: RailsPress provides drop-in blog functionality with categories, tags,
|
|
41
|
+
rich text editing, and an admin interface.
|
|
42
|
+
email:
|
|
43
|
+
- avi@flatironschool.com
|
|
44
|
+
executables: []
|
|
45
|
+
extensions: []
|
|
46
|
+
extra_rdoc_files: []
|
|
47
|
+
files:
|
|
48
|
+
- MIT-LICENSE
|
|
49
|
+
- README.md
|
|
50
|
+
- Rakefile
|
|
51
|
+
- app/assets/javascripts/railspress/admin.js
|
|
52
|
+
- app/assets/stylesheets/actiontext.css
|
|
53
|
+
- app/assets/stylesheets/railspress/admin.css
|
|
54
|
+
- app/assets/stylesheets/railspress/application.css
|
|
55
|
+
- app/controllers/railspress/admin/base_controller.rb
|
|
56
|
+
- app/controllers/railspress/admin/categories_controller.rb
|
|
57
|
+
- app/controllers/railspress/admin/dashboard_controller.rb
|
|
58
|
+
- app/controllers/railspress/admin/posts_controller.rb
|
|
59
|
+
- app/controllers/railspress/admin/tags_controller.rb
|
|
60
|
+
- app/controllers/railspress/application_controller.rb
|
|
61
|
+
- app/helpers/railspress/application_helper.rb
|
|
62
|
+
- app/jobs/railspress/application_job.rb
|
|
63
|
+
- app/mailers/railspress/application_mailer.rb
|
|
64
|
+
- app/models/railspress/application_record.rb
|
|
65
|
+
- app/models/railspress/category.rb
|
|
66
|
+
- app/models/railspress/post.rb
|
|
67
|
+
- app/models/railspress/post_tag.rb
|
|
68
|
+
- app/models/railspress/tag.rb
|
|
69
|
+
- app/views/active_storage/blobs/_blob.html.erb
|
|
70
|
+
- app/views/layouts/action_text/contents/_content.html.erb
|
|
71
|
+
- app/views/layouts/railspress/admin.html.erb
|
|
72
|
+
- app/views/layouts/railspress/application.html.erb
|
|
73
|
+
- app/views/railspress/admin/categories/_form.html.erb
|
|
74
|
+
- app/views/railspress/admin/categories/edit.html.erb
|
|
75
|
+
- app/views/railspress/admin/categories/index.html.erb
|
|
76
|
+
- app/views/railspress/admin/categories/new.html.erb
|
|
77
|
+
- app/views/railspress/admin/dashboard/index.html.erb
|
|
78
|
+
- app/views/railspress/admin/posts/_form.html.erb
|
|
79
|
+
- app/views/railspress/admin/posts/edit.html.erb
|
|
80
|
+
- app/views/railspress/admin/posts/index.html.erb
|
|
81
|
+
- app/views/railspress/admin/posts/new.html.erb
|
|
82
|
+
- app/views/railspress/admin/posts/show.html.erb
|
|
83
|
+
- app/views/railspress/admin/shared/_flash.html.erb
|
|
84
|
+
- app/views/railspress/admin/shared/_sidebar.html.erb
|
|
85
|
+
- app/views/railspress/admin/tags/_form.html.erb
|
|
86
|
+
- app/views/railspress/admin/tags/edit.html.erb
|
|
87
|
+
- app/views/railspress/admin/tags/index.html.erb
|
|
88
|
+
- app/views/railspress/admin/tags/new.html.erb
|
|
89
|
+
- config/routes.rb
|
|
90
|
+
- db/migrate/20241218000001_create_railspress_categories.rb
|
|
91
|
+
- db/migrate/20241218000002_create_railspress_tags.rb
|
|
92
|
+
- db/migrate/20241218000003_create_railspress_posts.rb
|
|
93
|
+
- db/migrate/20241218000004_create_railspress_post_tags.rb
|
|
94
|
+
- lib/generators/railspress/authors/authors_generator.rb
|
|
95
|
+
- lib/generators/railspress/authors/templates/add_author_to_railspress_posts.rb.tt
|
|
96
|
+
- lib/generators/railspress/authors/templates/railspress.rb.tt
|
|
97
|
+
- lib/generators/railspress/install/install_generator.rb
|
|
98
|
+
- lib/railspress.rb
|
|
99
|
+
- lib/railspress/engine.rb
|
|
100
|
+
- lib/railspress/version.rb
|
|
101
|
+
- lib/tasks/railspress_tasks.rake
|
|
102
|
+
homepage: https://github.com/aviflombaum/railspress-engine
|
|
103
|
+
licenses:
|
|
104
|
+
- MIT
|
|
105
|
+
metadata:
|
|
106
|
+
homepage_uri: https://github.com/aviflombaum/railspress-engine
|
|
107
|
+
source_code_uri: https://github.com/aviflombaum/railspress-engine
|
|
108
|
+
changelog_uri: https://github.com/aviflombaum/railspress-engine/blob/main/CHANGELOG.md
|
|
109
|
+
rubygems_mfa_required: 'true'
|
|
110
|
+
post_install_message: |2+
|
|
111
|
+
|
|
112
|
+
============================================================
|
|
113
|
+
RailsPress installed! Run the generator to complete setup:
|
|
114
|
+
|
|
115
|
+
$ rails generate railspress:install
|
|
116
|
+
|
|
117
|
+
This will:
|
|
118
|
+
- Copy database migrations
|
|
119
|
+
- Mount the engine in your routes
|
|
120
|
+
- Install ActionText (if needed)
|
|
121
|
+
============================================================
|
|
122
|
+
|
|
123
|
+
rdoc_options: []
|
|
124
|
+
require_paths:
|
|
125
|
+
- lib
|
|
126
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - ">="
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: 3.3.0
|
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
132
|
+
requirements:
|
|
133
|
+
- - ">="
|
|
134
|
+
- !ruby/object:Gem::Version
|
|
135
|
+
version: '0'
|
|
136
|
+
requirements: []
|
|
137
|
+
rubygems_version: 3.6.9
|
|
138
|
+
specification_version: 4
|
|
139
|
+
summary: A mountable blog engine for Rails 8+
|
|
140
|
+
test_files: []
|
|
141
|
+
...
|