not_pressed-core 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/LICENSE.txt +41 -0
- data/README.md +285 -0
- data/app/assets/javascripts/not_pressed/lightbox.js +110 -0
- data/app/assets/stylesheets/not_pressed/admin.css +1161 -0
- data/app/assets/stylesheets/not_pressed/content.css +193 -0
- data/app/assets/stylesheets/not_pressed/gallery.css +117 -0
- data/app/assets/stylesheets/not_pressed/themes/starter.css +118 -0
- data/app/controllers/not_pressed/admin/base_controller.rb +21 -0
- data/app/controllers/not_pressed/admin/categories_controller.rb +53 -0
- data/app/controllers/not_pressed/admin/content_blocks_controller.rb +73 -0
- data/app/controllers/not_pressed/admin/dashboard_controller.rb +19 -0
- data/app/controllers/not_pressed/admin/forms_controller.rb +86 -0
- data/app/controllers/not_pressed/admin/media_attachments_controller.rb +94 -0
- data/app/controllers/not_pressed/admin/pages_controller.rb +122 -0
- data/app/controllers/not_pressed/admin/plugins_controller.rb +121 -0
- data/app/controllers/not_pressed/admin/settings_controller.rb +19 -0
- data/app/controllers/not_pressed/admin/tags_controller.rb +37 -0
- data/app/controllers/not_pressed/admin/themes_controller.rb +104 -0
- data/app/controllers/not_pressed/application_controller.rb +6 -0
- data/app/controllers/not_pressed/blog_controller.rb +83 -0
- data/app/controllers/not_pressed/form_submissions_controller.rb +70 -0
- data/app/controllers/not_pressed/pages_controller.rb +36 -0
- data/app/controllers/not_pressed/robots_controller.rb +34 -0
- data/app/controllers/not_pressed/sitemaps_controller.rb +12 -0
- data/app/helpers/not_pressed/admin_helper.rb +41 -0
- data/app/helpers/not_pressed/application_helper.rb +6 -0
- data/app/helpers/not_pressed/code_injection_helper.rb +29 -0
- data/app/helpers/not_pressed/content_helper.rb +13 -0
- data/app/helpers/not_pressed/form_helper.rb +80 -0
- data/app/helpers/not_pressed/media_helper.rb +28 -0
- data/app/helpers/not_pressed/seo_helper.rb +69 -0
- data/app/helpers/not_pressed/theme_helper.rb +42 -0
- data/app/mailers/not_pressed/application_mailer.rb +10 -0
- data/app/mailers/not_pressed/form_mailer.rb +15 -0
- data/app/models/concerns/not_pressed/sluggable.rb +43 -0
- data/app/models/not_pressed/category.rb +16 -0
- data/app/models/not_pressed/content_block.rb +46 -0
- data/app/models/not_pressed/form.rb +55 -0
- data/app/models/not_pressed/form_field.rb +23 -0
- data/app/models/not_pressed/form_submission.rb +19 -0
- data/app/models/not_pressed/media_attachment.rb +68 -0
- data/app/models/not_pressed/page.rb +182 -0
- data/app/models/not_pressed/page_version.rb +15 -0
- data/app/models/not_pressed/setting.rb +20 -0
- data/app/models/not_pressed/tag.rb +15 -0
- data/app/models/not_pressed/tagging.rb +12 -0
- data/app/plugins/not_pressed/analytics_plugin.rb +106 -0
- data/app/plugins/not_pressed/callout_block_plugin.rb +43 -0
- data/app/themes/not_pressed/starter_theme.rb +26 -0
- data/app/views/layouts/not_pressed/admin.html.erb +745 -0
- data/app/views/layouts/not_pressed/application.html.erb +12 -0
- data/app/views/layouts/not_pressed/page.html.erb +22 -0
- data/app/views/not_pressed/admin/categories/index.html.erb +58 -0
- data/app/views/not_pressed/admin/content_blocks/_block.html.erb +18 -0
- data/app/views/not_pressed/admin/content_blocks/_block_picker.html.erb +32 -0
- data/app/views/not_pressed/admin/content_blocks/create.turbo_stream.erb +3 -0
- data/app/views/not_pressed/admin/content_blocks/destroy.turbo_stream.erb +1 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_callout.html.erb +38 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_code.html.erb +26 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_divider.html.erb +4 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_form.html.erb +16 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_gallery.html.erb +75 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_heading.html.erb +26 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_html.html.erb +13 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_image.html.erb +56 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_quote.html.erb +24 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_text.html.erb +28 -0
- data/app/views/not_pressed/admin/content_blocks/editors/_video.html.erb +25 -0
- data/app/views/not_pressed/admin/dashboard/index.html.erb +60 -0
- data/app/views/not_pressed/admin/forms/_field_row.html.erb +33 -0
- data/app/views/not_pressed/admin/forms/_form.html.erb +75 -0
- data/app/views/not_pressed/admin/forms/edit.html.erb +1 -0
- data/app/views/not_pressed/admin/forms/index.html.erb +32 -0
- data/app/views/not_pressed/admin/forms/new.html.erb +1 -0
- data/app/views/not_pressed/admin/forms/submissions.html.erb +34 -0
- data/app/views/not_pressed/admin/media_attachments/_media_card.html.erb +21 -0
- data/app/views/not_pressed/admin/media_attachments/_picker.html.erb +19 -0
- data/app/views/not_pressed/admin/media_attachments/edit.html.erb +57 -0
- data/app/views/not_pressed/admin/media_attachments/index.html.erb +48 -0
- data/app/views/not_pressed/admin/pages/_form.html.erb +177 -0
- data/app/views/not_pressed/admin/pages/_page_tree_node.html.erb +32 -0
- data/app/views/not_pressed/admin/pages/edit.html.erb +69 -0
- data/app/views/not_pressed/admin/pages/index.html.erb +21 -0
- data/app/views/not_pressed/admin/pages/new.html.erb +1 -0
- data/app/views/not_pressed/admin/pages/preview.html.erb +17 -0
- data/app/views/not_pressed/admin/plugins/_settings_form.html.erb +59 -0
- data/app/views/not_pressed/admin/plugins/index.html.erb +48 -0
- data/app/views/not_pressed/admin/plugins/show.html.erb +54 -0
- data/app/views/not_pressed/admin/settings/code_injection.html.erb +21 -0
- data/app/views/not_pressed/admin/shared/_breadcrumbs.html.erb +14 -0
- data/app/views/not_pressed/admin/shared/_flash.html.erb +7 -0
- data/app/views/not_pressed/admin/shared/_modal.html.erb +9 -0
- data/app/views/not_pressed/admin/shared/_sidebar.html.erb +18 -0
- data/app/views/not_pressed/admin/tags/index.html.erb +52 -0
- data/app/views/not_pressed/admin/themes/index.html.erb +60 -0
- data/app/views/not_pressed/admin/themes/show.html.erb +66 -0
- data/app/views/not_pressed/blog/_post_card.html.erb +24 -0
- data/app/views/not_pressed/blog/feed.rss.builder +22 -0
- data/app/views/not_pressed/blog/index.html.erb +56 -0
- data/app/views/not_pressed/blog/show.html.erb +41 -0
- data/app/views/not_pressed/form_mailer/submission_notification.text.erb +8 -0
- data/app/views/not_pressed/pages/show.html.erb +4 -0
- data/app/views/themes/starter/layouts/not_pressed/default.html.erb +36 -0
- data/app/views/themes/starter/layouts/not_pressed/full_width.html.erb +36 -0
- data/app/views/themes/starter/layouts/not_pressed/sidebar.html.erb +41 -0
- data/config/routes.rb +81 -0
- data/db/migrate/20260310000001_create_not_pressed_pages.rb +20 -0
- data/db/migrate/20260310000002_create_not_pressed_content_blocks.rb +17 -0
- data/db/migrate/20260310000003_create_not_pressed_media_attachments.rb +14 -0
- data/db/migrate/20260310000004_add_content_type_to_not_pressed_pages.rb +8 -0
- data/db/migrate/20260310000005_add_publishing_fields_to_not_pressed_pages.rb +8 -0
- data/db/migrate/20260310000006_create_not_pressed_page_versions.rb +16 -0
- data/db/migrate/20260310000007_add_settings_fields_to_not_pressed_pages.rb +11 -0
- data/db/migrate/20260311000001_create_not_pressed_forms.rb +42 -0
- data/db/migrate/20260311000002_add_seo_fields_to_not_pressed_pages.rb +10 -0
- data/db/migrate/20260311000003_add_code_injection_to_not_pressed_pages.rb +8 -0
- data/db/migrate/20260311000004_create_not_pressed_settings.rb +14 -0
- data/db/migrate/20260312000001_create_not_pressed_categories.rb +16 -0
- data/db/migrate/20260312000002_create_not_pressed_tags.rb +15 -0
- data/db/migrate/20260312000003_create_not_pressed_taggings.rb +14 -0
- data/db/migrate/20260312000004_add_category_id_to_not_pressed_pages.rb +7 -0
- data/lib/generators/not_pressed/install/install_generator.rb +52 -0
- data/lib/generators/not_pressed/install/templates/initializer.rb.tt +89 -0
- data/lib/generators/not_pressed/install/templates/seeds.rb.tt +131 -0
- data/lib/generators/not_pressed/plugin/plugin_generator.rb +37 -0
- data/lib/generators/not_pressed/plugin/templates/plugin.rb.tt +23 -0
- data/lib/not_pressed/admin/authentication.rb +48 -0
- data/lib/not_pressed/admin/menu_registry.rb +100 -0
- data/lib/not_pressed/configuration.rb +77 -0
- data/lib/not_pressed/content_type.rb +23 -0
- data/lib/not_pressed/content_type_builder.rb +51 -0
- data/lib/not_pressed/content_type_registry.rb +45 -0
- data/lib/not_pressed/engine.rb +132 -0
- data/lib/not_pressed/hooks.rb +166 -0
- data/lib/not_pressed/navigation/builder.rb +148 -0
- data/lib/not_pressed/navigation/menu.rb +54 -0
- data/lib/not_pressed/navigation/menu_item.rb +33 -0
- data/lib/not_pressed/navigation/node.rb +45 -0
- data/lib/not_pressed/navigation/partial_parser.rb +96 -0
- data/lib/not_pressed/navigation/route_inspector.rb +98 -0
- data/lib/not_pressed/navigation.rb +6 -0
- data/lib/not_pressed/plugin.rb +354 -0
- data/lib/not_pressed/plugin_importer.rb +133 -0
- data/lib/not_pressed/plugin_manager.rb +196 -0
- data/lib/not_pressed/plugin_packager.rb +129 -0
- data/lib/not_pressed/rendering/block_renderer.rb +222 -0
- data/lib/not_pressed/rendering/renderer_registry.rb +154 -0
- data/lib/not_pressed/rendering.rb +8 -0
- data/lib/not_pressed/seo/sitemap_builder.rb +61 -0
- data/lib/not_pressed/theme.rb +191 -0
- data/lib/not_pressed/theme_importer.rb +133 -0
- data/lib/not_pressed/theme_packager.rb +180 -0
- data/lib/not_pressed/theme_registry.rb +123 -0
- data/lib/not_pressed/version.rb +5 -0
- data/lib/not_pressed.rb +65 -0
- metadata +258 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<%= seo_meta_tags(@page, request) %>
|
|
7
|
+
<%= stylesheet_link_tag "not_pressed/content", media: "all" %>
|
|
8
|
+
<%= stylesheet_link_tag "not_pressed/gallery", media: "all" %>
|
|
9
|
+
<%= theme_stylesheet_tag %>
|
|
10
|
+
<%= theme_color_overrides %>
|
|
11
|
+
<%= csrf_meta_tags %>
|
|
12
|
+
<%= csp_meta_tag %>
|
|
13
|
+
<%= head_injection(@page) %>
|
|
14
|
+
</head>
|
|
15
|
+
<body class="np-page-body <%= active_theme_class %>">
|
|
16
|
+
<header class="np-theme-header">
|
|
17
|
+
<div class="np-theme-header-inner">
|
|
18
|
+
<a href="/" class="np-theme-site-name"><%= NotPressed.configuration.site_name %></a>
|
|
19
|
+
</div>
|
|
20
|
+
</header>
|
|
21
|
+
|
|
22
|
+
<main class="np-theme-main">
|
|
23
|
+
<div class="np-theme-content--full-width">
|
|
24
|
+
<%= yield %>
|
|
25
|
+
</div>
|
|
26
|
+
</main>
|
|
27
|
+
|
|
28
|
+
<footer class="np-theme-footer">
|
|
29
|
+
<div class="np-theme-footer-inner">
|
|
30
|
+
<p>© <%= Date.current.year %> <%= NotPressed.configuration.site_name %></p>
|
|
31
|
+
</div>
|
|
32
|
+
</footer>
|
|
33
|
+
<%= javascript_include_tag "not_pressed/lightbox" %>
|
|
34
|
+
<%= body_injection(@page) %>
|
|
35
|
+
</body>
|
|
36
|
+
</html>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<%= seo_meta_tags(@page, request) %>
|
|
7
|
+
<%= stylesheet_link_tag "not_pressed/content", media: "all" %>
|
|
8
|
+
<%= stylesheet_link_tag "not_pressed/gallery", media: "all" %>
|
|
9
|
+
<%= theme_stylesheet_tag %>
|
|
10
|
+
<%= theme_color_overrides %>
|
|
11
|
+
<%= csrf_meta_tags %>
|
|
12
|
+
<%= csp_meta_tag %>
|
|
13
|
+
<%= head_injection(@page) %>
|
|
14
|
+
</head>
|
|
15
|
+
<body class="np-page-body <%= active_theme_class %>">
|
|
16
|
+
<header class="np-theme-header">
|
|
17
|
+
<div class="np-theme-header-inner">
|
|
18
|
+
<a href="/" class="np-theme-site-name"><%= NotPressed.configuration.site_name %></a>
|
|
19
|
+
</div>
|
|
20
|
+
</header>
|
|
21
|
+
|
|
22
|
+
<main class="np-theme-main">
|
|
23
|
+
<div class="np-theme-layout-sidebar">
|
|
24
|
+
<div class="np-theme-content">
|
|
25
|
+
<%= yield %>
|
|
26
|
+
</div>
|
|
27
|
+
<aside class="np-theme-sidebar">
|
|
28
|
+
<%= yield :sidebar if content_for?(:sidebar) %>
|
|
29
|
+
</aside>
|
|
30
|
+
</div>
|
|
31
|
+
</main>
|
|
32
|
+
|
|
33
|
+
<footer class="np-theme-footer">
|
|
34
|
+
<div class="np-theme-footer-inner">
|
|
35
|
+
<p>© <%= Date.current.year %> <%= NotPressed.configuration.site_name %></p>
|
|
36
|
+
</div>
|
|
37
|
+
</footer>
|
|
38
|
+
<%= javascript_include_tag "not_pressed/lightbox" %>
|
|
39
|
+
<%= body_injection(@page) %>
|
|
40
|
+
</body>
|
|
41
|
+
</html>
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
NotPressed::Engine.routes.draw do
|
|
4
|
+
namespace :admin do
|
|
5
|
+
root to: "dashboard#index"
|
|
6
|
+
resources :forms, except: [:show] do
|
|
7
|
+
member do
|
|
8
|
+
get :submissions
|
|
9
|
+
get :export_csv
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
resource :settings, only: [] do
|
|
13
|
+
get :code_injection
|
|
14
|
+
patch :code_injection, action: :update_code_injection
|
|
15
|
+
end
|
|
16
|
+
resources :media_attachments, only: [:index, :create, :edit, :update, :destroy], path: "media" do
|
|
17
|
+
get :picker, on: :collection
|
|
18
|
+
end
|
|
19
|
+
resources :themes, only: [:index, :show], param: :theme_name do
|
|
20
|
+
member do
|
|
21
|
+
post :activate
|
|
22
|
+
post :deactivate
|
|
23
|
+
patch :update_colors
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
resources :plugins, only: [:index, :show], param: :plugin_name do
|
|
27
|
+
member do
|
|
28
|
+
post :toggle
|
|
29
|
+
patch :update_settings
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
get "themes/:id/export", to: "themes#export", as: :export_theme
|
|
33
|
+
post "themes/import", to: "themes#import", as: :import_theme
|
|
34
|
+
get "plugins/:id/export", to: "plugins#export", as: :export_plugin
|
|
35
|
+
post "plugins/import", to: "plugins#import", as: :import_plugin
|
|
36
|
+
resources :categories, only: [:index, :create, :update, :destroy]
|
|
37
|
+
resources :tags, only: [:index, :create, :destroy]
|
|
38
|
+
resources :pages do
|
|
39
|
+
collection do
|
|
40
|
+
patch :reorder
|
|
41
|
+
end
|
|
42
|
+
resources :content_blocks, only: [:create, :update, :destroy] do
|
|
43
|
+
collection do
|
|
44
|
+
patch :reorder
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
member do
|
|
48
|
+
get :preview
|
|
49
|
+
post :duplicate
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Plugin routes
|
|
54
|
+
NotPressed::PluginManager.registered.each do |_name, info|
|
|
55
|
+
next unless info[:status] == :active
|
|
56
|
+
info[:klass].plugin_routes.each do |route_block|
|
|
57
|
+
instance_exec(&route_block)
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Sitemap & Robots
|
|
63
|
+
get "sitemap.xml", to: "sitemaps#show", as: :sitemap, defaults: { format: :xml }
|
|
64
|
+
get "robots.txt", to: "robots#show", as: :robots, defaults: { format: :text }
|
|
65
|
+
|
|
66
|
+
# Public form submission route
|
|
67
|
+
post "forms/:form_slug/submit", to: "form_submissions#create", as: :form_submissions
|
|
68
|
+
|
|
69
|
+
# Blog routes
|
|
70
|
+
get "blog", to: "blog#index", as: :blog
|
|
71
|
+
get "blog/feed.rss", to: "blog#feed", as: :blog_feed, defaults: { format: :rss }
|
|
72
|
+
get "blog/category/:slug", to: "blog#category", as: :blog_category
|
|
73
|
+
get "blog/tag/:slug", to: "blog#tag", as: :blog_tag
|
|
74
|
+
get "blog/archive/:year(/:month)", to: "blog#archive", as: :blog_archive
|
|
75
|
+
get "blog/:slug", to: "blog#show", as: :blog_post
|
|
76
|
+
|
|
77
|
+
# Public page route
|
|
78
|
+
get ":slug", to: "pages#show", as: :page, constraints: { slug: /[a-z0-9]+(?:-[a-z0-9]+)*/ }
|
|
79
|
+
|
|
80
|
+
root to: "admin/dashboard#index"
|
|
81
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateNotPressedPages < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :not_pressed_pages do |t|
|
|
6
|
+
t.string :title, null: false
|
|
7
|
+
t.string :slug, null: false
|
|
8
|
+
t.text :meta_description
|
|
9
|
+
t.integer :status, default: 0, null: false
|
|
10
|
+
t.integer :position, default: 0, null: false
|
|
11
|
+
t.references :parent, foreign_key: { to_table: :not_pressed_pages }, null: true
|
|
12
|
+
|
|
13
|
+
t.timestamps
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
add_index :not_pressed_pages, :slug, unique: true
|
|
17
|
+
add_index :not_pressed_pages, :status
|
|
18
|
+
add_index :not_pressed_pages, [:parent_id, :position]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateNotPressedContentBlocks < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :not_pressed_content_blocks do |t|
|
|
6
|
+
t.references :page, null: false, foreign_key: { to_table: :not_pressed_pages }
|
|
7
|
+
t.string :block_type, null: false
|
|
8
|
+
t.json :content, default: {}
|
|
9
|
+
t.integer :position, default: 0, null: false
|
|
10
|
+
|
|
11
|
+
t.timestamps
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
add_index :not_pressed_content_blocks, [:page_id, :position]
|
|
15
|
+
add_index :not_pressed_content_blocks, :block_type
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateNotPressedMediaAttachments < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :not_pressed_media_attachments do |t|
|
|
6
|
+
t.string :title
|
|
7
|
+
t.string :alt_text
|
|
8
|
+
t.string :content_type
|
|
9
|
+
t.integer :file_size
|
|
10
|
+
t.json :metadata, default: {}
|
|
11
|
+
t.timestamps
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateNotPressedPageVersions < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :not_pressed_page_versions do |t|
|
|
6
|
+
t.references :page, null: false, foreign_key: { to_table: :not_pressed_pages }
|
|
7
|
+
t.integer :version_number, null: false
|
|
8
|
+
t.json :snapshot, null: false
|
|
9
|
+
t.string :event, null: false
|
|
10
|
+
|
|
11
|
+
t.datetime :created_at, null: false
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
add_index :not_pressed_page_versions, [:page_id, :version_number], unique: true
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddSettingsFieldsToNotPressedPages < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
add_column :not_pressed_pages, :meta_title, :string
|
|
6
|
+
add_column :not_pressed_pages, :og_image_url, :string
|
|
7
|
+
add_column :not_pressed_pages, :layout, :string
|
|
8
|
+
add_column :not_pressed_pages, :visibility, :integer, default: 0, null: false
|
|
9
|
+
add_column :not_pressed_pages, :password_digest, :string
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateNotPressedForms < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :not_pressed_forms do |t|
|
|
6
|
+
t.string :name, null: false
|
|
7
|
+
t.string :slug, null: false
|
|
8
|
+
t.text :description
|
|
9
|
+
t.string :email_recipient
|
|
10
|
+
t.string :redirect_url
|
|
11
|
+
t.text :success_message, default: "Thank you for your submission."
|
|
12
|
+
t.integer :status, default: 0, null: false
|
|
13
|
+
t.integer :submissions_count, default: 0, null: false
|
|
14
|
+
|
|
15
|
+
t.timestamps
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
add_index :not_pressed_forms, :slug, unique: true
|
|
19
|
+
|
|
20
|
+
create_table :not_pressed_form_fields do |t|
|
|
21
|
+
t.references :form, null: false, foreign_key: { to_table: :not_pressed_forms }
|
|
22
|
+
t.string :label, null: false
|
|
23
|
+
t.integer :field_type, default: 0, null: false
|
|
24
|
+
t.boolean :required, default: false
|
|
25
|
+
t.string :placeholder
|
|
26
|
+
t.json :options
|
|
27
|
+
t.integer :position, default: 0, null: false
|
|
28
|
+
|
|
29
|
+
t.timestamps
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
add_index :not_pressed_form_fields, [:form_id, :position]
|
|
33
|
+
|
|
34
|
+
create_table :not_pressed_form_submissions do |t|
|
|
35
|
+
t.references :form, null: false, foreign_key: { to_table: :not_pressed_forms }
|
|
36
|
+
t.json :data, null: false
|
|
37
|
+
t.datetime :submitted_at, null: false
|
|
38
|
+
|
|
39
|
+
t.timestamps
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class AddSeoFieldsToNotPressedPages < ActiveRecord::Migration[8.1]
|
|
4
|
+
def change
|
|
5
|
+
add_column :not_pressed_pages, :canonical_url, :string
|
|
6
|
+
add_column :not_pressed_pages, :meta_robots, :string
|
|
7
|
+
add_column :not_pressed_pages, :og_type, :string, default: "website"
|
|
8
|
+
add_column :not_pressed_pages, :twitter_card, :string, default: "summary"
|
|
9
|
+
end
|
|
10
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateNotPressedSettings < ActiveRecord::Migration[8.1]
|
|
4
|
+
def change
|
|
5
|
+
create_table :not_pressed_settings do |t|
|
|
6
|
+
t.string :key, null: false
|
|
7
|
+
t.text :value
|
|
8
|
+
|
|
9
|
+
t.timestamps
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
add_index :not_pressed_settings, :key, unique: true
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateNotPressedCategories < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :not_pressed_categories do |t|
|
|
6
|
+
t.string :name, null: false
|
|
7
|
+
t.string :slug, null: false
|
|
8
|
+
t.text :description
|
|
9
|
+
|
|
10
|
+
t.timestamps
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
add_index :not_pressed_categories, :name, unique: true
|
|
14
|
+
add_index :not_pressed_categories, :slug, unique: true
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateNotPressedTags < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :not_pressed_tags do |t|
|
|
6
|
+
t.string :name, null: false
|
|
7
|
+
t.string :slug, null: false
|
|
8
|
+
|
|
9
|
+
t.timestamps
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
add_index :not_pressed_tags, :name, unique: true
|
|
13
|
+
add_index :not_pressed_tags, :slug, unique: true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class CreateNotPressedTaggings < ActiveRecord::Migration[8.0]
|
|
4
|
+
def change
|
|
5
|
+
create_table :not_pressed_taggings do |t|
|
|
6
|
+
t.references :tag, null: false, foreign_key: { to_table: :not_pressed_tags }
|
|
7
|
+
t.references :page, null: false, foreign_key: { to_table: :not_pressed_pages }
|
|
8
|
+
|
|
9
|
+
t.timestamps
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
add_index :not_pressed_taggings, [:tag_id, :page_id], unique: true
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators/base"
|
|
4
|
+
|
|
5
|
+
module NotPressed
|
|
6
|
+
module Generators
|
|
7
|
+
class InstallGenerator < Rails::Generators::Base
|
|
8
|
+
source_root File.expand_path("templates", __dir__)
|
|
9
|
+
|
|
10
|
+
desc "Install NotPressed CMS into your Rails application"
|
|
11
|
+
|
|
12
|
+
def copy_initializer
|
|
13
|
+
template "initializer.rb.tt", "config/initializers/not_pressed.rb"
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def copy_seeds
|
|
17
|
+
template "seeds.rb.tt", "db/seeds/not_pressed.rb"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def mount_engine
|
|
21
|
+
route 'mount NotPressed::Engine, at: "/not_pressed"'
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def copy_migrations
|
|
25
|
+
rake "not_pressed:install:migrations"
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def check_active_storage
|
|
29
|
+
unless defined?(ActiveStorage)
|
|
30
|
+
say "WARNING: Active Storage is not installed.", :yellow
|
|
31
|
+
say " Run: rails active_storage:install"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def show_post_install
|
|
36
|
+
say ""
|
|
37
|
+
say "NotPressed installed!", :green
|
|
38
|
+
say ""
|
|
39
|
+
say "Next steps:"
|
|
40
|
+
say " 1. Run `rails db:migrate` to set up the database"
|
|
41
|
+
say " 2. Load seed data by adding this to db/seeds.rb:"
|
|
42
|
+
say " load 'db/seeds/not_pressed.rb'"
|
|
43
|
+
say " Then run `rails db:seed`"
|
|
44
|
+
say " 3. Visit /not_pressed/admin to manage your site"
|
|
45
|
+
say " 4. Visit /not_pressed/blog to see the blog"
|
|
46
|
+
say " 5. Edit config/initializers/not_pressed.rb to customize settings"
|
|
47
|
+
say " 6. Import plugins and themes from the admin panel"
|
|
48
|
+
say ""
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# NotPressed CMS Configuration
|
|
2
|
+
#
|
|
3
|
+
# Customize your NotPressed installation below.
|
|
4
|
+
# Uncomment and modify any setting to override the defaults.
|
|
5
|
+
|
|
6
|
+
NotPressed.configure do |config|
|
|
7
|
+
# ---------------------------------------------------------------------------
|
|
8
|
+
# Site Settings
|
|
9
|
+
# ---------------------------------------------------------------------------
|
|
10
|
+
|
|
11
|
+
# Site name displayed in the admin header and SEO tags.
|
|
12
|
+
# config.site_name = "My Site"
|
|
13
|
+
|
|
14
|
+
# Default number of items per page in admin listings.
|
|
15
|
+
# config.per_page = 25
|
|
16
|
+
|
|
17
|
+
# Separator between page title and site name in browser title bar.
|
|
18
|
+
# config.seo_title_separator = " | "
|
|
19
|
+
|
|
20
|
+
# ---------------------------------------------------------------------------
|
|
21
|
+
# Admin Authentication
|
|
22
|
+
# ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
# Proc that guards admin access. Return true to allow, false to deny.
|
|
25
|
+
# config.admin_authentication = ->(controller) { controller.current_user&.admin? }
|
|
26
|
+
|
|
27
|
+
# Proc that returns the current admin user (used for audit trails).
|
|
28
|
+
# config.admin_current_user = ->(controller) { controller.current_user }
|
|
29
|
+
|
|
30
|
+
# Path to redirect to when admin authentication fails.
|
|
31
|
+
# config.admin_unauthorized_redirect = "/"
|
|
32
|
+
|
|
33
|
+
# URL path prefix for admin routes.
|
|
34
|
+
# config.admin_path = "not_pressed"
|
|
35
|
+
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
# Layouts & Themes
|
|
38
|
+
# ---------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
# Available layout names for pages (themes may add additional layouts).
|
|
41
|
+
# config.available_layouts = ["default"]
|
|
42
|
+
|
|
43
|
+
# Name of the default theme to activate on startup.
|
|
44
|
+
# config.default_theme = "Starter"
|
|
45
|
+
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
# Navigation
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
# Automatically discover navigable routes from your app.
|
|
51
|
+
# config.auto_discover_navigation = true
|
|
52
|
+
|
|
53
|
+
# Cache the discovered navigation structure for performance.
|
|
54
|
+
# config.cache_navigation = true
|
|
55
|
+
|
|
56
|
+
# Define a custom navigation menu:
|
|
57
|
+
# config.menu(:main) do
|
|
58
|
+
# item "Home", "/"
|
|
59
|
+
# item "Blog", "/not_pressed/blog"
|
|
60
|
+
# item "About", "/not_pressed/about"
|
|
61
|
+
# end
|
|
62
|
+
|
|
63
|
+
# ---------------------------------------------------------------------------
|
|
64
|
+
# Global Code Injection
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
|
|
67
|
+
# HTML injected into the <head> of every public page (analytics, fonts, etc.)
|
|
68
|
+
# config.global_head_code = nil
|
|
69
|
+
|
|
70
|
+
# HTML injected before the closing </body> of every public page.
|
|
71
|
+
# config.global_body_code = nil
|
|
72
|
+
|
|
73
|
+
# Custom robots.txt content (overrides the auto-generated one).
|
|
74
|
+
# config.robots_txt = nil
|
|
75
|
+
|
|
76
|
+
# ---------------------------------------------------------------------------
|
|
77
|
+
# Custom Content Types (Blog is built-in)
|
|
78
|
+
# ---------------------------------------------------------------------------
|
|
79
|
+
# Define custom content types using the DSL:
|
|
80
|
+
#
|
|
81
|
+
# NotPressed.define_content_type(:event) do
|
|
82
|
+
# label "Event"
|
|
83
|
+
# icon "calendar"
|
|
84
|
+
# description "An event page"
|
|
85
|
+
# field :event_date, :datetime, label: "Event Date", required: true
|
|
86
|
+
# field :venue, :string, label: "Venue"
|
|
87
|
+
# field :ticket_url, :url, label: "Ticket URL"
|
|
88
|
+
# end
|
|
89
|
+
end
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# NotPressed CMS — Sample Seed Data
|
|
2
|
+
#
|
|
3
|
+
# Load this file from db/seeds.rb:
|
|
4
|
+
# load "db/seeds/not_pressed.rb"
|
|
5
|
+
|
|
6
|
+
puts "Seeding NotPressed CMS..."
|
|
7
|
+
|
|
8
|
+
# ---------------------------------------------------------------------------
|
|
9
|
+
# Pages
|
|
10
|
+
# ---------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
home = NotPressed::Page.find_or_create_by!(slug: "home") do |p|
|
|
13
|
+
p.title = "Home"
|
|
14
|
+
p.content_type = "page"
|
|
15
|
+
p.status = :published
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
NotPressed::ContentBlock.find_or_create_by!(page: home, position: 0) do |b|
|
|
19
|
+
b.block_type = "heading"
|
|
20
|
+
b.content = { "text" => "Welcome to Your Site", "level" => 1 }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
NotPressed::ContentBlock.find_or_create_by!(page: home, position: 1) do |b|
|
|
24
|
+
b.block_type = "text"
|
|
25
|
+
b.content = { "body" => "<p>This is your new site powered by NotPressed CMS. Edit this page from the admin panel.</p>" }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
about = NotPressed::Page.find_or_create_by!(slug: "about") do |p|
|
|
29
|
+
p.title = "About"
|
|
30
|
+
p.content_type = "page"
|
|
31
|
+
p.status = :published
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
NotPressed::ContentBlock.find_or_create_by!(page: about, position: 0) do |b|
|
|
35
|
+
b.block_type = "heading"
|
|
36
|
+
b.content = { "text" => "About Us", "level" => 1 }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
NotPressed::ContentBlock.find_or_create_by!(page: about, position: 1) do |b|
|
|
40
|
+
b.block_type = "text"
|
|
41
|
+
b.content = { "body" => "<p>Tell your visitors about your site, team, or mission.</p>" }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
NotPressed::ContentBlock.find_or_create_by!(page: about, position: 2) do |b|
|
|
45
|
+
b.block_type = "text"
|
|
46
|
+
b.content = { "body" => "<p>This is a second content block — you can add as many as you need.</p>" }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
contact = NotPressed::Page.find_or_create_by!(slug: "contact") do |p|
|
|
50
|
+
p.title = "Contact"
|
|
51
|
+
p.content_type = "page"
|
|
52
|
+
p.status = :draft
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
NotPressed::ContentBlock.find_or_create_by!(page: contact, position: 0) do |b|
|
|
56
|
+
b.block_type = "heading"
|
|
57
|
+
b.content = { "text" => "Get in Touch", "level" => 1 }
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
NotPressed::ContentBlock.find_or_create_by!(page: contact, position: 1) do |b|
|
|
61
|
+
b.block_type = "text"
|
|
62
|
+
b.content = { "body" => "<p>Drop us a line — we'd love to hear from you.</p>" }
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# ---------------------------------------------------------------------------
|
|
66
|
+
# Blog — Categories & Tags
|
|
67
|
+
# ---------------------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
general = NotPressed::Category.find_or_create_by!(name: "General")
|
|
70
|
+
|
|
71
|
+
welcome_tag = NotPressed::Tag.find_or_create_by!(name: "welcome")
|
|
72
|
+
news_tag = NotPressed::Tag.find_or_create_by!(name: "news")
|
|
73
|
+
updates_tag = NotPressed::Tag.find_or_create_by!(name: "updates")
|
|
74
|
+
|
|
75
|
+
# ---------------------------------------------------------------------------
|
|
76
|
+
# Blog Posts
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
post1 = NotPressed::Page.find_or_create_by!(slug: "welcome-to-not-pressed") do |p|
|
|
80
|
+
p.title = "Welcome to NotPressed"
|
|
81
|
+
p.content_type = "blog_post"
|
|
82
|
+
p.status = :published
|
|
83
|
+
p.category = general
|
|
84
|
+
p.published_at = Time.current
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
NotPressed::ContentBlock.find_or_create_by!(page: post1, position: 0) do |b|
|
|
88
|
+
b.block_type = "heading"
|
|
89
|
+
b.content = { "text" => "Welcome to NotPressed", "level" => 2 }
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
NotPressed::ContentBlock.find_or_create_by!(page: post1, position: 1) do |b|
|
|
93
|
+
b.block_type = "text"
|
|
94
|
+
b.content = { "body" => "<p>Your new blog is ready! Start writing posts from the admin panel at <code>/not_pressed/admin</code>.</p>" }
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
[welcome_tag, news_tag].each do |tag|
|
|
98
|
+
NotPressed::Tagging.find_or_create_by!(page: post1, tag: tag)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
post2 = NotPressed::Page.find_or_create_by!(slug: "getting-started") do |p|
|
|
102
|
+
p.title = "Getting Started"
|
|
103
|
+
p.content_type = "blog_post"
|
|
104
|
+
p.status = :published
|
|
105
|
+
p.category = general
|
|
106
|
+
p.published_at = 1.hour.ago
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
NotPressed::ContentBlock.find_or_create_by!(page: post2, position: 0) do |b|
|
|
110
|
+
b.block_type = "heading"
|
|
111
|
+
b.content = { "text" => "Getting Started with NotPressed", "level" => 2 }
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
NotPressed::ContentBlock.find_or_create_by!(page: post2, position: 1) do |b|
|
|
115
|
+
b.block_type = "text"
|
|
116
|
+
b.content = { "body" => "<p>Learn how to create pages, manage content blocks, and customize your theme.</p>" }
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
NotPressed::ContentBlock.find_or_create_by!(page: post2, position: 2) do |b|
|
|
120
|
+
b.block_type = "text"
|
|
121
|
+
b.content = { "body" => "<p>Check out the documentation for more advanced features like custom content types and plugins.</p>" }
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
[news_tag, updates_tag].each do |tag|
|
|
125
|
+
NotPressed::Tagging.find_or_create_by!(page: post2, tag: tag)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
puts "NotPressed seeding complete!"
|
|
129
|
+
puts " 3 pages (Home, About, Contact)"
|
|
130
|
+
puts " 2 blog posts (Welcome, Getting Started)"
|
|
131
|
+
puts " 1 category, 3 tags"
|