cms42 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 +21 -0
- data/README.md +299 -0
- data/Rakefile +10 -0
- data/app/assets/stylesheets/cms/application.css +3 -0
- data/app/controllers/cms/admin/api_keys_controller.rb +52 -0
- data/app/controllers/cms/admin/base_controller.rb +54 -0
- data/app/controllers/cms/admin/documents_controller.rb +56 -0
- data/app/controllers/cms/admin/form_fields_controller.rb +70 -0
- data/app/controllers/cms/admin/form_submissions_controller.rb +36 -0
- data/app/controllers/cms/admin/images_controller.rb +67 -0
- data/app/controllers/cms/admin/pages_controller.rb +188 -0
- data/app/controllers/cms/admin/sections_controller.rb +177 -0
- data/app/controllers/cms/admin/sites_controller.rb +60 -0
- data/app/controllers/cms/admin/webhook_deliveries_controller.rb +19 -0
- data/app/controllers/cms/admin/webhooks_controller.rb +51 -0
- data/app/controllers/cms/api/base_controller.rb +45 -0
- data/app/controllers/cms/api/v1/base_controller.rb +29 -0
- data/app/controllers/cms/api/v1/pages_controller.rb +21 -0
- data/app/controllers/cms/api/v1/sites_controller.rb +18 -0
- data/app/controllers/cms/application_controller.rb +11 -0
- data/app/controllers/cms/public/base_controller.rb +23 -0
- data/app/controllers/cms/public/form_submissions_controller.rb +63 -0
- data/app/controllers/cms/public/previews_controller.rb +21 -0
- data/app/controllers/cms/public/sites_controller.rb +37 -0
- data/app/controllers/concerns/cms/admin/page_scoped_sections.rb +42 -0
- data/app/controllers/concerns/cms/current_site_resolver.rb +17 -0
- data/app/controllers/concerns/cms/public/page_paths.rb +31 -0
- data/app/controllers/concerns/cms/public/page_rendering.rb +23 -0
- data/app/controllers/concerns/cms/site_resolvable.rb +27 -0
- data/app/helpers/cms/admin/pages_helper.rb +29 -0
- data/app/helpers/cms/admin/sections_helper.rb +86 -0
- data/app/helpers/cms/admin/sites_helper.rb +8 -0
- data/app/helpers/cms/application_helper.rb +51 -0
- data/app/helpers/cms/media_helper.rb +28 -0
- data/app/helpers/cms/pages_helper.rb +16 -0
- data/app/helpers/cms/sections_helper.rb +25 -0
- data/app/helpers/cms/sites_helper.rb +11 -0
- data/app/javascript/cms/controllers/sortable_controller.js +38 -0
- data/app/jobs/cms/application_job.rb +6 -0
- data/app/jobs/cms/deliver_webhook_job.rb +66 -0
- data/app/mailers/cms/application_mailer.rb +9 -0
- data/app/mailers/cms/form_submission_mailer.rb +16 -0
- data/app/models/cms/api_key.rb +27 -0
- data/app/models/cms/application_record.rb +7 -0
- data/app/models/cms/document.rb +48 -0
- data/app/models/cms/form_field.rb +27 -0
- data/app/models/cms/form_submission.rb +42 -0
- data/app/models/cms/image.rb +61 -0
- data/app/models/cms/image_translation.rb +22 -0
- data/app/models/cms/page.rb +228 -0
- data/app/models/cms/page_section.rb +43 -0
- data/app/models/cms/page_translation.rb +22 -0
- data/app/models/cms/section/block_base.rb +32 -0
- data/app/models/cms/section/blocks/call_to_action_block.rb +16 -0
- data/app/models/cms/section/blocks/hero_block.rb +14 -0
- data/app/models/cms/section/blocks/image_block.rb +13 -0
- data/app/models/cms/section/blocks/rich_text_block.rb +12 -0
- data/app/models/cms/section/kind_registry.rb +66 -0
- data/app/models/cms/section.rb +94 -0
- data/app/models/cms/section_image.rb +10 -0
- data/app/models/cms/section_translation.rb +25 -0
- data/app/models/cms/site.rb +87 -0
- data/app/models/cms/webhook.rb +41 -0
- data/app/models/cms/webhook_delivery.rb +12 -0
- data/app/serializers/cms/api/base_serializer.rb +51 -0
- data/app/serializers/cms/api/page_serializer.rb +145 -0
- data/app/serializers/cms/api/site_serializer.rb +45 -0
- data/app/services/cms/locale_resolver.rb +30 -0
- data/app/services/cms/page_resolver.rb +73 -0
- data/app/services/cms/public_page_context.rb +49 -0
- data/app/views/cms/admin/api_keys/_form.html.erb +23 -0
- data/app/views/cms/admin/api_keys/create.html.erb +9 -0
- data/app/views/cms/admin/api_keys/edit.html.erb +5 -0
- data/app/views/cms/admin/api_keys/index.html.erb +36 -0
- data/app/views/cms/admin/api_keys/new.html.erb +5 -0
- data/app/views/cms/admin/documents/_form.html.erb +24 -0
- data/app/views/cms/admin/documents/edit.html.erb +2 -0
- data/app/views/cms/admin/documents/index.html.erb +37 -0
- data/app/views/cms/admin/documents/new.html.erb +2 -0
- data/app/views/cms/admin/form_fields/_form.html.erb +46 -0
- data/app/views/cms/admin/form_fields/edit.html.erb +2 -0
- data/app/views/cms/admin/form_fields/index.html.erb +41 -0
- data/app/views/cms/admin/form_fields/new.html.erb +2 -0
- data/app/views/cms/admin/form_submissions/index.html.erb +38 -0
- data/app/views/cms/admin/images/_form.html.erb +36 -0
- data/app/views/cms/admin/images/edit.html.erb +2 -0
- data/app/views/cms/admin/images/index.html.erb +25 -0
- data/app/views/cms/admin/images/new.html.erb +2 -0
- data/app/views/cms/admin/pages/_attach_section_panel.html.erb +20 -0
- data/app/views/cms/admin/pages/_form.html.erb +116 -0
- data/app/views/cms/admin/pages/_section_editor_frame.html.erb +3 -0
- data/app/views/cms/admin/pages/_sections_list.html.erb +9 -0
- data/app/views/cms/admin/pages/edit.html.erb +2 -0
- data/app/views/cms/admin/pages/index.html.erb +62 -0
- data/app/views/cms/admin/pages/new.html.erb +2 -0
- data/app/views/cms/admin/pages/show.html.erb +111 -0
- data/app/views/cms/admin/sections/_form.html.erb +128 -0
- data/app/views/cms/admin/sections/_section.html.erb +22 -0
- data/app/views/cms/admin/sections/edit.html.erb +9 -0
- data/app/views/cms/admin/sections/index.html.erb +47 -0
- data/app/views/cms/admin/sections/new.html.erb +9 -0
- data/app/views/cms/admin/sections/page_update.turbo_stream.erb +17 -0
- data/app/views/cms/admin/sections/show.html.erb +97 -0
- data/app/views/cms/admin/sites/_form.html.erb +44 -0
- data/app/views/cms/admin/sites/edit.html.erb +3 -0
- data/app/views/cms/admin/sites/new.html.erb +5 -0
- data/app/views/cms/admin/sites/show.html.erb +22 -0
- data/app/views/cms/admin/webhook_deliveries/index.html.erb +29 -0
- data/app/views/cms/admin/webhooks/_form.html.erb +38 -0
- data/app/views/cms/admin/webhooks/edit.html.erb +5 -0
- data/app/views/cms/admin/webhooks/index.html.erb +34 -0
- data/app/views/cms/admin/webhooks/new.html.erb +5 -0
- data/app/views/cms/form_submission_mailer/notify.html.erb +14 -0
- data/app/views/cms/form_submission_mailer/notify.text.erb +7 -0
- data/app/views/cms/public/pages/_content.html.erb +48 -0
- data/app/views/cms/public/pages/show.html.erb +44 -0
- data/app/views/cms/public/pages/templates/_custom.html.erb +3 -0
- data/app/views/cms/public/pages/templates/_form.html.erb +3 -0
- data/app/views/cms/public/pages/templates/_landing.html.erb +3 -0
- data/app/views/cms/public/pages/templates/_standard.html.erb +3 -0
- data/app/views/cms/sections/kinds/_cta.html.erb +13 -0
- data/app/views/cms/sections/kinds/_hero.html.erb +14 -0
- data/app/views/cms/sections/kinds/_image.html.erb +19 -0
- data/app/views/cms/sections/kinds/_rich_text.html.erb +6 -0
- data/app/views/layouts/cms/application.html.erb +13 -0
- data/app/views/layouts/cms/public.html.erb +14 -0
- data/bin/rails +19 -0
- data/bin/rubocop +9 -0
- data/cms.gemspec +29 -0
- data/config/importmap.rb +4 -0
- data/config/locales/activerecord.cms.en.yml +65 -0
- data/config/locales/en.yml +390 -0
- data/config/routes.rb +56 -0
- data/lib/cms/engine.rb +45 -0
- data/lib/cms/version.rb +5 -0
- data/lib/cms.rb +75 -0
- data/lib/cms42.rb +3 -0
- data/lib/generators/cms/install/install_generator.rb +26 -0
- data/lib/generators/cms/install/templates/create_cms_tables.rb +194 -0
- data/lib/generators/cms/install/templates/initializer.rb +21 -0
- data/lib/generators/cms/views/views_generator.rb +79 -0
- data/lib/tasks/cms_tasks.rake +6 -0
- data/lib/tasks/version.rake +8 -0
- metadata +281 -0
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
en:
|
|
2
|
+
date:
|
|
3
|
+
formats:
|
|
4
|
+
cms_date: "%d %b %Y"
|
|
5
|
+
time:
|
|
6
|
+
formats:
|
|
7
|
+
cms_csv_datetime: "%Y-%m-%d %H:%M"
|
|
8
|
+
cms_datetime: "%d %b %Y %H:%M"
|
|
9
|
+
cms:
|
|
10
|
+
shared:
|
|
11
|
+
empty_value: "-"
|
|
12
|
+
no: "No"
|
|
13
|
+
yes: "Yes"
|
|
14
|
+
errors:
|
|
15
|
+
admin_parent_controller_required: "Cms admin requires config.admin_parent_controller in production. Point it at a host controller that enforces authentication, for example \"Admin::BaseController\"."
|
|
16
|
+
current_site_required: "Cms admin requires config.current_site_resolver to return a Cms::Site. Configure it in Cms.setup so admin requests resolve the active CMS site explicitly."
|
|
17
|
+
page_not_found: "Page not found"
|
|
18
|
+
record_not_found: "The requested record was not found."
|
|
19
|
+
site_slug_not_provided: "CMS site slug not provided"
|
|
20
|
+
api:
|
|
21
|
+
site_not_found: "Site not found"
|
|
22
|
+
page_not_found: "Page not found"
|
|
23
|
+
unauthorized: "Unauthorized"
|
|
24
|
+
form_field:
|
|
25
|
+
invalid_field_name: "only lowercase letters, numbers and underscores"
|
|
26
|
+
form_submission:
|
|
27
|
+
blank: "Please complete at least one field."
|
|
28
|
+
required: "%{label} is required"
|
|
29
|
+
document:
|
|
30
|
+
invalid_file_type: "must be a supported document file"
|
|
31
|
+
image:
|
|
32
|
+
invalid_file_type: "must be a valid image file"
|
|
33
|
+
section:
|
|
34
|
+
setting_required: "%{name} is required"
|
|
35
|
+
invalid_image: "contains an image that is not available for this site"
|
|
36
|
+
global_section_requires_attachment: "A global section must stay attached to at least one page."
|
|
37
|
+
page:
|
|
38
|
+
sections_required: "Published pages must have at least one section."
|
|
39
|
+
site:
|
|
40
|
+
default_locale_unavailable: "is not included in I18n.available_locales"
|
|
41
|
+
webhook:
|
|
42
|
+
unsupported_events: "contains unsupported values: %{events}"
|
|
43
|
+
notices:
|
|
44
|
+
form_submission_sent: "Your message has been sent."
|
|
45
|
+
site_created: "Site created."
|
|
46
|
+
site_updated: "Site updated."
|
|
47
|
+
page_created: "Page created."
|
|
48
|
+
page_updated: "Page updated."
|
|
49
|
+
page_deleted: "Page deleted."
|
|
50
|
+
section_added: "Section added."
|
|
51
|
+
section_created: "Section created."
|
|
52
|
+
section_updated: "Section updated."
|
|
53
|
+
section_deleted: "Section deleted."
|
|
54
|
+
section_removed: "Section removed from page."
|
|
55
|
+
section_attached: "Section attached."
|
|
56
|
+
field_added: "Field added."
|
|
57
|
+
field_updated: "Field updated."
|
|
58
|
+
field_removed: "Field removed."
|
|
59
|
+
submission_deleted: "Submission deleted."
|
|
60
|
+
image_uploaded: "Image uploaded."
|
|
61
|
+
image_updated: "Image updated."
|
|
62
|
+
image_deleted: "Image deleted."
|
|
63
|
+
document_uploaded: "Document uploaded."
|
|
64
|
+
document_updated: "Document updated."
|
|
65
|
+
document_deleted: "Document deleted."
|
|
66
|
+
api_key_updated: "API key updated."
|
|
67
|
+
api_key_deleted: "API key deleted."
|
|
68
|
+
webhook_created: "Webhook created."
|
|
69
|
+
webhook_updated: "Webhook updated."
|
|
70
|
+
webhook_deleted: "Webhook deleted."
|
|
71
|
+
mailers:
|
|
72
|
+
form_submission:
|
|
73
|
+
subject: "New form submission - %{page_title}"
|
|
74
|
+
form_field_kinds:
|
|
75
|
+
checkbox: "Checkbox"
|
|
76
|
+
email: "Email"
|
|
77
|
+
select: "Select"
|
|
78
|
+
text: "Text"
|
|
79
|
+
textarea: "Textarea"
|
|
80
|
+
form_submission_mailer:
|
|
81
|
+
notify:
|
|
82
|
+
submitted_at: "Submitted at"
|
|
83
|
+
title: "New form submission — %{page}"
|
|
84
|
+
page_statuses:
|
|
85
|
+
archived: "Archived"
|
|
86
|
+
draft: "Draft"
|
|
87
|
+
published: "Published"
|
|
88
|
+
page_templates:
|
|
89
|
+
custom: "Custom"
|
|
90
|
+
form: "Form"
|
|
91
|
+
landing: "Landing"
|
|
92
|
+
standard: "Standard"
|
|
93
|
+
public:
|
|
94
|
+
forms:
|
|
95
|
+
send: "Send"
|
|
96
|
+
contact: "Contact"
|
|
97
|
+
submission_problem: "There was a problem with your submission"
|
|
98
|
+
section_kinds:
|
|
99
|
+
cta: "Call to action"
|
|
100
|
+
hero: "Hero"
|
|
101
|
+
image: "Image"
|
|
102
|
+
rich_text: "Rich text"
|
|
103
|
+
section_settings:
|
|
104
|
+
labels:
|
|
105
|
+
alignment: "Alignment"
|
|
106
|
+
alt_text: "Alt text"
|
|
107
|
+
background_color: "Background color"
|
|
108
|
+
button_text: "Button text"
|
|
109
|
+
button_url: "Button URL"
|
|
110
|
+
caption: "Caption"
|
|
111
|
+
cta_text: "CTA text"
|
|
112
|
+
cta_url: "CTA URL"
|
|
113
|
+
image_url: "Image URL"
|
|
114
|
+
options:
|
|
115
|
+
alignment:
|
|
116
|
+
center: "Center"
|
|
117
|
+
left: "Left"
|
|
118
|
+
right: "Right"
|
|
119
|
+
webhook_events:
|
|
120
|
+
page_published: "Page published"
|
|
121
|
+
page_unpublished: "Page unpublished"
|
|
122
|
+
admin:
|
|
123
|
+
api_keys:
|
|
124
|
+
create:
|
|
125
|
+
back: "Back to API keys"
|
|
126
|
+
title: "API Key Created"
|
|
127
|
+
token_warning: "Copy your API token now — it will not be shown again:"
|
|
128
|
+
edit:
|
|
129
|
+
back: "Back"
|
|
130
|
+
title: "Edit API Key"
|
|
131
|
+
index:
|
|
132
|
+
active: "Active"
|
|
133
|
+
created: "Created"
|
|
134
|
+
delete: "Delete"
|
|
135
|
+
delete_confirm: "Delete this API key?"
|
|
136
|
+
edit: "Edit"
|
|
137
|
+
empty: "No API keys yet."
|
|
138
|
+
last_used: "Last used"
|
|
139
|
+
name: "Name"
|
|
140
|
+
never: "Never"
|
|
141
|
+
new: "New API Key"
|
|
142
|
+
title: "API Keys"
|
|
143
|
+
new:
|
|
144
|
+
back: "Back"
|
|
145
|
+
title: "New API Key"
|
|
146
|
+
documents:
|
|
147
|
+
edit:
|
|
148
|
+
title: "Edit Document — %{title}"
|
|
149
|
+
form:
|
|
150
|
+
cancel: "Cancel"
|
|
151
|
+
current: "Current"
|
|
152
|
+
file: "File"
|
|
153
|
+
index:
|
|
154
|
+
actions: "Actions"
|
|
155
|
+
delete: "Delete"
|
|
156
|
+
delete_confirm: "Delete this document?"
|
|
157
|
+
description: "Description"
|
|
158
|
+
edit: "Edit"
|
|
159
|
+
empty: "No documents yet."
|
|
160
|
+
file: "File"
|
|
161
|
+
title: "Documents"
|
|
162
|
+
title_heading: "Title"
|
|
163
|
+
upload: "Upload document"
|
|
164
|
+
new:
|
|
165
|
+
title: "Upload Document"
|
|
166
|
+
form_fields:
|
|
167
|
+
edit:
|
|
168
|
+
title: "Edit field — %{label}"
|
|
169
|
+
form:
|
|
170
|
+
cancel: "Cancel"
|
|
171
|
+
field_name: "Field name (snake_case, used as data key)"
|
|
172
|
+
hint: "Hint text shown below the field"
|
|
173
|
+
options: "Options (for select fields, one per line)"
|
|
174
|
+
index:
|
|
175
|
+
actions: "Actions"
|
|
176
|
+
back: "Back to page"
|
|
177
|
+
delete: "Delete"
|
|
178
|
+
delete_confirm: "Delete this field?"
|
|
179
|
+
edit: "Edit"
|
|
180
|
+
empty: "No fields yet. Add fields to build your form."
|
|
181
|
+
field_name: "Field name"
|
|
182
|
+
kind: "Kind"
|
|
183
|
+
label: "Label"
|
|
184
|
+
new: "New field"
|
|
185
|
+
required: "Required"
|
|
186
|
+
submissions: "View submissions"
|
|
187
|
+
title: "Form fields — %{page}"
|
|
188
|
+
new:
|
|
189
|
+
title: "New form field — %{page}"
|
|
190
|
+
form_submissions:
|
|
191
|
+
index:
|
|
192
|
+
actions: "Actions"
|
|
193
|
+
back: "Back to form fields"
|
|
194
|
+
delete: "Delete"
|
|
195
|
+
delete_confirm: "Delete this submission?"
|
|
196
|
+
empty: "No submissions yet."
|
|
197
|
+
export: "Export CSV"
|
|
198
|
+
submitted_at: "Submitted at"
|
|
199
|
+
title: "Submissions — %{page}"
|
|
200
|
+
images:
|
|
201
|
+
edit:
|
|
202
|
+
title: "Edit Image — %{title}"
|
|
203
|
+
form:
|
|
204
|
+
alt_text: "Alt text"
|
|
205
|
+
cancel: "Cancel"
|
|
206
|
+
file: "Image file"
|
|
207
|
+
translation: "Translation (%{locale})"
|
|
208
|
+
index:
|
|
209
|
+
delete: "Delete"
|
|
210
|
+
delete_confirm: "Delete this image?"
|
|
211
|
+
edit: "Edit"
|
|
212
|
+
empty: "No images yet."
|
|
213
|
+
title: "Images"
|
|
214
|
+
upload: "Upload image"
|
|
215
|
+
new:
|
|
216
|
+
title: "Upload Image"
|
|
217
|
+
pages:
|
|
218
|
+
edit:
|
|
219
|
+
title: "Edit Page"
|
|
220
|
+
form:
|
|
221
|
+
cancel: "Cancel"
|
|
222
|
+
current_files: "Current files"
|
|
223
|
+
media_files: "Gallery/attachments"
|
|
224
|
+
no_parent: "— none (root page)"
|
|
225
|
+
parent_page: "Parent page"
|
|
226
|
+
remove_hero_image: "Remove hero image"
|
|
227
|
+
remove_media_files: "Remove all gallery/attachments"
|
|
228
|
+
seo_description: "SEO description"
|
|
229
|
+
seo_title: "SEO title"
|
|
230
|
+
template: "Template"
|
|
231
|
+
title: "Title"
|
|
232
|
+
translation: "Translation (%{locale})"
|
|
233
|
+
translation_title: "Title"
|
|
234
|
+
index:
|
|
235
|
+
actions: "Actions"
|
|
236
|
+
clear: "Clear"
|
|
237
|
+
delete: "Delete"
|
|
238
|
+
delete_confirm: "Delete this page?"
|
|
239
|
+
edit: "Edit"
|
|
240
|
+
empty: "No pages yet. Create your first page to start building the site."
|
|
241
|
+
empty_search: "No pages matched your search."
|
|
242
|
+
footer: "footer"
|
|
243
|
+
header: "header"
|
|
244
|
+
intro: "Pages are listed in site order. Use parent pages for simple hierarchies and search when you need to jump straight to one page."
|
|
245
|
+
nav: "Nav"
|
|
246
|
+
new: "New page"
|
|
247
|
+
search: "Search"
|
|
248
|
+
search_placeholder: "Search by title or slug…"
|
|
249
|
+
site_settings: "Website settings"
|
|
250
|
+
slug: "Slug"
|
|
251
|
+
status: "Status"
|
|
252
|
+
template: "Template"
|
|
253
|
+
title: "Pages"
|
|
254
|
+
title_heading: "Title"
|
|
255
|
+
view: "View"
|
|
256
|
+
new:
|
|
257
|
+
title: "New Page"
|
|
258
|
+
show:
|
|
259
|
+
add_section: "+ Add section"
|
|
260
|
+
attach: "Attach section"
|
|
261
|
+
attach_existing: "Attach global section"
|
|
262
|
+
attachments: "Attachments"
|
|
263
|
+
back: "Back"
|
|
264
|
+
content_sections: "Content sections"
|
|
265
|
+
edit: "Edit"
|
|
266
|
+
footer: "Footer"
|
|
267
|
+
form_fields: "Form fields"
|
|
268
|
+
header: "Header"
|
|
269
|
+
hero_image: "Hero image"
|
|
270
|
+
home_page: "Home page"
|
|
271
|
+
locale: "Locale"
|
|
272
|
+
meta_description: "Meta description"
|
|
273
|
+
meta_title: "Meta title"
|
|
274
|
+
nav_group: "Nav group"
|
|
275
|
+
no_title: "(no title)"
|
|
276
|
+
parent: "Parent"
|
|
277
|
+
preview: "Preview"
|
|
278
|
+
share_preview: "Share preview"
|
|
279
|
+
section_hint: "Select a section type above to add content."
|
|
280
|
+
select_global: "Select a global section"
|
|
281
|
+
slug: "Slug"
|
|
282
|
+
status: "Status"
|
|
283
|
+
submissions: "Submissions"
|
|
284
|
+
subpages: "Subpages"
|
|
285
|
+
template: "Template"
|
|
286
|
+
translation_missing_badge: "%{locale}: missing"
|
|
287
|
+
translation_missing_title: "%{locale}: missing"
|
|
288
|
+
translations: "Translations"
|
|
289
|
+
sections:
|
|
290
|
+
edit:
|
|
291
|
+
title: "Edit section — %{kind}"
|
|
292
|
+
form:
|
|
293
|
+
add: "Add section"
|
|
294
|
+
cancel: "Cancel"
|
|
295
|
+
content: "Content"
|
|
296
|
+
content_placeholder: "Rich text content"
|
|
297
|
+
image_library_empty: "Upload images in the media library before using this block."
|
|
298
|
+
kind: "Kind"
|
|
299
|
+
manage_images: "Manage images"
|
|
300
|
+
select_image: "Select image"
|
|
301
|
+
settings: "Block settings"
|
|
302
|
+
upload_image: "Upload image"
|
|
303
|
+
update: "Update section"
|
|
304
|
+
index:
|
|
305
|
+
actions: "Actions"
|
|
306
|
+
back: "Back to pages"
|
|
307
|
+
delete: "Delete"
|
|
308
|
+
delete_confirm: "Delete this section everywhere it is used?"
|
|
309
|
+
disabled: "Disabled"
|
|
310
|
+
edit: "Edit"
|
|
311
|
+
empty: "No global sections yet."
|
|
312
|
+
enabled: "Enabled"
|
|
313
|
+
intro: "Manage site-wide global sections here and attach them to pages where needed."
|
|
314
|
+
kind: "Kind"
|
|
315
|
+
new: "New global section"
|
|
316
|
+
no_title: "(no title)"
|
|
317
|
+
status: "Status"
|
|
318
|
+
title: "Sections"
|
|
319
|
+
title_heading: "Title"
|
|
320
|
+
unused: "Not attached"
|
|
321
|
+
usage: "Used on"
|
|
322
|
+
new:
|
|
323
|
+
title: "Add section — %{kind}"
|
|
324
|
+
show:
|
|
325
|
+
details: "Section details"
|
|
326
|
+
global: "Global"
|
|
327
|
+
no_translation: "No translation for this locale."
|
|
328
|
+
section:
|
|
329
|
+
delete: "Delete"
|
|
330
|
+
delete_confirm: "Remove this section?"
|
|
331
|
+
disabled: "Disabled"
|
|
332
|
+
drag: "Drag to reorder"
|
|
333
|
+
edit: "Edit"
|
|
334
|
+
enabled: "Enabled"
|
|
335
|
+
no_title: "(no title)"
|
|
336
|
+
sites:
|
|
337
|
+
new:
|
|
338
|
+
title: "Create Website"
|
|
339
|
+
intro: "Create the first CMS site before managing pages, media, and settings."
|
|
340
|
+
edit:
|
|
341
|
+
title: "Edit Website Settings"
|
|
342
|
+
show:
|
|
343
|
+
title: "Website Settings"
|
|
344
|
+
public_url: "Public URL"
|
|
345
|
+
published: "Published"
|
|
346
|
+
default_locale: "Default locale"
|
|
347
|
+
available_locales: "Available locales"
|
|
348
|
+
logo: "Logo"
|
|
349
|
+
logo_alt: "%{site} logo"
|
|
350
|
+
logo_hint: "The logo is also used as the site's favicon."
|
|
351
|
+
edit: "Edit site"
|
|
352
|
+
manage_pages: "Manage pages"
|
|
353
|
+
form:
|
|
354
|
+
logo_alt: "%{site} logo"
|
|
355
|
+
logo_hint: "Used for both the site logo and favicon."
|
|
356
|
+
remove_logo: "Remove logo"
|
|
357
|
+
create: "Create site"
|
|
358
|
+
save: "Save"
|
|
359
|
+
cancel: "Cancel"
|
|
360
|
+
webhook_deliveries:
|
|
361
|
+
index:
|
|
362
|
+
back: "Back to webhooks"
|
|
363
|
+
delivered_at: "Delivered at"
|
|
364
|
+
empty: "No deliveries yet."
|
|
365
|
+
error: "Error"
|
|
366
|
+
event: "Event"
|
|
367
|
+
response_code: "Response code"
|
|
368
|
+
status: "Success"
|
|
369
|
+
title: "Deliveries — %{url}"
|
|
370
|
+
webhooks:
|
|
371
|
+
edit:
|
|
372
|
+
back: "Back"
|
|
373
|
+
title: "Edit Webhook"
|
|
374
|
+
form:
|
|
375
|
+
events: "Events"
|
|
376
|
+
secret: "Secret (optional — used for HMAC signature)"
|
|
377
|
+
url: "Endpoint URL"
|
|
378
|
+
index:
|
|
379
|
+
active: "Active"
|
|
380
|
+
delete: "Delete"
|
|
381
|
+
delete_confirm: "Delete this webhook?"
|
|
382
|
+
edit: "Edit"
|
|
383
|
+
empty: "No webhooks yet."
|
|
384
|
+
events: "Events"
|
|
385
|
+
new: "New Webhook"
|
|
386
|
+
title: "Webhooks"
|
|
387
|
+
url: "URL"
|
|
388
|
+
new:
|
|
389
|
+
back: "Back"
|
|
390
|
+
title: "New Webhook"
|
data/config/routes.rb
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
Cms::Engine.routes.draw do
|
|
4
|
+
namespace :admin do
|
|
5
|
+
resource :site, only: %i[new create show edit update]
|
|
6
|
+
resources :sections
|
|
7
|
+
resources :pages do
|
|
8
|
+
member do
|
|
9
|
+
get :preview
|
|
10
|
+
end
|
|
11
|
+
patch "sections/sort", to: "sections#sort", as: :sort_sections
|
|
12
|
+
resources :sections, except: :index
|
|
13
|
+
post "sections/attach", to: "sections#attach", as: :attach_section
|
|
14
|
+
resources :form_fields do
|
|
15
|
+
collection do
|
|
16
|
+
patch :sort
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
resources :form_submissions, only: %i[index destroy]
|
|
20
|
+
end
|
|
21
|
+
resources :images
|
|
22
|
+
resources :documents
|
|
23
|
+
resources :api_keys, except: %i[show]
|
|
24
|
+
resources :webhooks, except: %i[show] do
|
|
25
|
+
resources :deliveries, only: :index, controller: "webhook_deliveries"
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
namespace :api, defaults: { format: :json } do
|
|
30
|
+
namespace :v1 do
|
|
31
|
+
resources :sites, only: :show, param: :site_slug do
|
|
32
|
+
resources :pages, only: :show, param: :slug
|
|
33
|
+
end
|
|
34
|
+
resource :site, only: :show, controller: :sites
|
|
35
|
+
resources :pages, only: :show, param: :slug
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
scope module: :public do
|
|
40
|
+
# Public form submissions
|
|
41
|
+
resources :pages, only: [] do
|
|
42
|
+
resources :form_submissions, only: :create
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Public multi-site routes (site resolved via URL slug)
|
|
46
|
+
resources :sites, only: :show, param: :site_slug
|
|
47
|
+
get "sites/:site_slug/*slug", to: "sites#show", as: :site_page
|
|
48
|
+
|
|
49
|
+
# Draft preview (token-based, no auth required)
|
|
50
|
+
get "preview/:preview_token", to: "previews#show", as: :page_preview
|
|
51
|
+
|
|
52
|
+
# Public single-site routes (site resolved via header/subdomain)
|
|
53
|
+
get "/", to: "sites#show", as: :current_site
|
|
54
|
+
get "*slug", to: "sites#show", as: :current_site_page
|
|
55
|
+
end
|
|
56
|
+
end
|
data/lib/cms/engine.rb
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "action_text/engine"
|
|
4
|
+
|
|
5
|
+
module Cms
|
|
6
|
+
class Engine < ::Rails::Engine
|
|
7
|
+
isolate_namespace Cms
|
|
8
|
+
|
|
9
|
+
initializer "cms.assets.precompile" do |app|
|
|
10
|
+
app.config.assets.precompile += %w[cms/application.css cms/application.js]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
initializer "cms.importmap", before: "importmap" do |app|
|
|
14
|
+
if app.config.respond_to?(:importmap)
|
|
15
|
+
app.config.importmap.paths << Engine.root.join("config/importmap.rb")
|
|
16
|
+
app.config.importmap.cache_sweepers << Engine.root.join("app/javascript")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
config.after_initialize do
|
|
21
|
+
if Rails.env.production? && Cms.config.admin_parent_controller.blank?
|
|
22
|
+
raise "Cms: admin_parent_controller must be configured in production. " \
|
|
23
|
+
"Set it in your Cms.setup block, e.g.: config.admin_parent_controller = \"AdminController\""
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
config.to_prepare do
|
|
28
|
+
# Section block classes
|
|
29
|
+
section_block_classes = {
|
|
30
|
+
"rich_text" => Cms::Section::Blocks::RichTextBlock,
|
|
31
|
+
"image" => Cms::Section::Blocks::ImageBlock,
|
|
32
|
+
"hero" => Cms::Section::Blocks::HeroBlock,
|
|
33
|
+
"cta" => Cms::Section::Blocks::CallToActionBlock
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
Cms::Section::KindRegistry::BUILT_IN_KINDS.each do |kind|
|
|
37
|
+
Cms::Section::KindRegistry.register(kind, block_class: section_block_classes[kind])
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
Array(Cms.config.page_templates).each do |key|
|
|
41
|
+
Cms::Page::TemplateRegistry.register(key)
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
data/lib/cms/version.rb
ADDED
data/lib/cms.rb
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "discard"
|
|
4
|
+
require "cms/version"
|
|
5
|
+
require "cms/engine"
|
|
6
|
+
|
|
7
|
+
module Cms
|
|
8
|
+
class Configuration
|
|
9
|
+
attr_accessor :parent_controller,
|
|
10
|
+
:admin_parent_controller,
|
|
11
|
+
:current_site_resolver,
|
|
12
|
+
:form_submission_email,
|
|
13
|
+
:mailer_from,
|
|
14
|
+
:image_renditions,
|
|
15
|
+
:page_templates,
|
|
16
|
+
:page_resolver_class,
|
|
17
|
+
:api_site_serializer_class,
|
|
18
|
+
:api_page_serializer_class,
|
|
19
|
+
:admin_layout,
|
|
20
|
+
:public_layout,
|
|
21
|
+
:authorize_admin,
|
|
22
|
+
:auto_destroy_orphaned_sections
|
|
23
|
+
|
|
24
|
+
def initialize
|
|
25
|
+
@parent_controller = "ApplicationController"
|
|
26
|
+
@admin_parent_controller = nil
|
|
27
|
+
@admin_layout = "cms/application"
|
|
28
|
+
@public_layout = "cms/public"
|
|
29
|
+
@image_renditions = {}
|
|
30
|
+
@page_templates = []
|
|
31
|
+
@page_resolver_class = "Cms::PageResolver"
|
|
32
|
+
@api_site_serializer_class = "Cms::Api::SiteSerializer"
|
|
33
|
+
@api_page_serializer_class = "Cms::Api::PageSerializer"
|
|
34
|
+
@mailer_from = nil
|
|
35
|
+
@authorize_admin = nil
|
|
36
|
+
@auto_destroy_orphaned_sections = false
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class << self
|
|
41
|
+
def config
|
|
42
|
+
@config ||= Configuration.new
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def setup
|
|
46
|
+
yield config
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def parent_controller
|
|
50
|
+
config.parent_controller
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def parent_controller=(val)
|
|
54
|
+
config.parent_controller = val
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def page_resolver_class
|
|
58
|
+
constantize_config_value(config.page_resolver_class)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def api_site_serializer_class
|
|
62
|
+
constantize_config_value(config.api_site_serializer_class)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def api_page_serializer_class
|
|
66
|
+
constantize_config_value(config.api_page_serializer_class)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
private
|
|
70
|
+
|
|
71
|
+
def constantize_config_value(value)
|
|
72
|
+
value.is_a?(String) ? value.constantize : value
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
data/lib/cms42.rb
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/active_record"
|
|
5
|
+
|
|
6
|
+
module Cms
|
|
7
|
+
module Generators
|
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
|
9
|
+
include Rails::Generators::Migration
|
|
10
|
+
|
|
11
|
+
source_root File.expand_path("templates", __dir__)
|
|
12
|
+
|
|
13
|
+
def create_migrations
|
|
14
|
+
migration_template "create_cms_tables.rb", "db/migrate/create_cms_tables.rb"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def copy_initializer
|
|
18
|
+
template "initializer.rb", "config/initializers/cms.rb"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.next_migration_number(dirname)
|
|
22
|
+
ActiveRecord::Generators::Base.next_migration_number(dirname)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|