wcc-contentful-app 0.4.0.pre.rc → 1.0.0.pre.rc1

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.
Files changed (94) hide show
  1. checksums.yaml +5 -5
  2. data/.rspec +2 -2
  3. data/Guardfile +1 -1
  4. data/README.md +11 -0
  5. data/Rakefile +121 -0
  6. data/app/assets/config/manifest.js +5 -0
  7. data/app/assets/images/down-arrow-primary.svg +3 -0
  8. data/app/assets/images/up-arrow-primary.svg +3 -0
  9. data/app/assets/javascripts/wcc/contentful/app/contact-form.js +70 -0
  10. data/app/assets/javascripts/wcc/contentful/app/index.js +1 -0
  11. data/app/assets/stylesheets/_wcc-contentful-app.scss +7 -0
  12. data/app/assets/stylesheets/components/_menu-item.scss +5 -0
  13. data/app/assets/stylesheets/sections/_faq.scss +39 -0
  14. data/app/controllers/wcc/contentful/app/contact_form_controller.rb +39 -0
  15. data/app/controllers/wcc/contentful/app/pages_controller.rb +48 -0
  16. data/app/helpers/wcc/contentful/app/menu_helper.rb +85 -0
  17. data/app/helpers/wcc/contentful/app/section_helper.rb +135 -0
  18. data/app/mailers/wcc/contentful/app/contact_mailer.rb +11 -0
  19. data/app/models/concerns/wcc/contentful/app/preview_password.rb +19 -0
  20. data/app/models/wcc/contentful/app/contact_form_submission.rb +9 -0
  21. data/app/models/wcc/contentful/app/custom_markdown_render.rb +43 -0
  22. data/app/views/components/_faq_row.html.erb +21 -0
  23. data/app/views/components/_menu-item.html.erb +41 -0
  24. data/app/views/components/_other-menu-item.html.erb +4 -0
  25. data/app/views/components/_section.html.erb +11 -0
  26. data/app/views/layouts/mailer.html.erb +9 -0
  27. data/app/views/layouts/mailer.text.erb +1 -0
  28. data/app/views/pages/show.html.erb +4 -0
  29. data/app/views/sections/_block_text.html.erb +5 -0
  30. data/app/views/sections/_code_widget.html.erb +3 -0
  31. data/app/views/sections/_contact_form.html.erb +53 -0
  32. data/app/views/sections/_faq.html.erb +36 -0
  33. data/app/views/sections/_http_error.html.erb +13 -0
  34. data/app/views/sections/_marquee_text.html.erb +12 -0
  35. data/app/views/sections/_testimonials.html.erb +38 -0
  36. data/app/views/sections/_video.html.erb +12 -0
  37. data/app/views/sections/_video_highlight.html.erb +18 -0
  38. data/app/views/wcc/contentful/app/contact_mailer/contact_form_email.html.erb +7 -0
  39. data/bin/rails +14 -0
  40. data/config/routes.rb +7 -0
  41. data/lib/generators/wcc/model_generator.rb +16 -6
  42. data/lib/generators/wcc/templates/menu/migrations/generated_add_menus.ts +285 -0
  43. data/lib/generators/wcc/templates/menu/models/dropdown_menu.rb +19 -0
  44. data/lib/generators/wcc/templates/menu/models/menu.rb +0 -4
  45. data/lib/generators/wcc/templates/menu/models/menu_button.rb +0 -4
  46. data/lib/generators/wcc/templates/page/migrations/generated_add_pages.ts +147 -0
  47. data/lib/generators/wcc/templates/page/models/page.rb +0 -4
  48. data/lib/generators/wcc/templates/page/models/redirect.rb +19 -0
  49. data/lib/generators/wcc/templates/section-block-text/migrations/generated_add_section-block-texts.ts +40 -0
  50. data/lib/generators/wcc/templates/section-block-text/models/section_block_text.rb +19 -0
  51. data/lib/generators/wcc/templates/section-code-widget/migrations/generated_add_section-code-widget.ts +90 -0
  52. data/lib/generators/wcc/templates/section-code-widget/models/section_code_widget.rb +23 -0
  53. data/lib/generators/wcc/templates/section-contact-form/migrations/create_wcc_contentful_app_contact_form_submissions.rb +12 -0
  54. data/lib/generators/wcc/templates/section-contact-form/migrations/generated_add_section-contact-forms.ts +147 -0
  55. data/lib/generators/wcc/templates/section-contact-form/models/form_field.rb +19 -0
  56. data/lib/generators/wcc/templates/section-contact-form/models/section_contact_form.rb +19 -0
  57. data/lib/generators/wcc/templates/section-faq/migrations/generated_add_section-faqs.ts +148 -0
  58. data/lib/generators/wcc/templates/section-faq/models/section_faq.rb +19 -0
  59. data/lib/generators/wcc/templates/section-http-error/migrations/generated_add_section-http-errors.ts +87 -0
  60. data/lib/generators/wcc/templates/section-http-error/models/section_http_error.rb +19 -0
  61. data/lib/generators/wcc/templates/section-marquee-text/migrations/generated_add_section-marquee-texts.ts +64 -0
  62. data/lib/generators/wcc/templates/section-marquee-text/models/section_marquee_text.rb +19 -0
  63. data/lib/generators/wcc/templates/section-testimonial/migrations/generated_add_section-testimonials.ts +182 -0
  64. data/lib/generators/wcc/templates/section-testimonial/models/section_testimonial.rb +19 -0
  65. data/lib/generators/wcc/templates/section-video-highlight/migrations/generated_add_section-video-highlights.ts +80 -0
  66. data/lib/generators/wcc/templates/section-video-highlight/models/section_video_highlight.rb +19 -0
  67. data/lib/generators/wcc/templates/section-video/migrations/generated_add_section-videos.ts +77 -0
  68. data/lib/generators/wcc/templates/section-video/models/section_video.rb +19 -0
  69. data/lib/generators/wcc/templates/site-config/migrations/generated_add_site-configs.ts +97 -0
  70. data/lib/generators/wcc/templates/site-config/models/site_config.rb +19 -0
  71. data/lib/generators/wcc/templates/wcc_contentful.rb +1 -1
  72. data/lib/wcc/contentful/app.rb +46 -3
  73. data/lib/wcc/contentful/app/configuration.rb +60 -0
  74. data/lib/wcc/contentful/app/engine.rb +15 -0
  75. data/lib/wcc/contentful/app/exceptions.rb +9 -0
  76. data/lib/wcc/contentful/app/rails.rb +6 -0
  77. data/lib/wcc/contentful/app/version.rb +1 -1
  78. data/lib/wcc/contentful/model/dropdown_menu.rb +0 -3
  79. data/lib/wcc/contentful/model/form_field.rb +4 -0
  80. data/lib/wcc/contentful/model/menu.rb +0 -2
  81. data/lib/wcc/contentful/model/menu_button.rb +18 -5
  82. data/lib/wcc/contentful/model/page.rb +0 -4
  83. data/lib/wcc/contentful/model/redirect.rb +21 -11
  84. data/lib/wcc/contentful/model/section_contact_form.rb +42 -0
  85. data/lib/wcc/contentful/model/site_config.rb +7 -0
  86. data/wcc-contentful-app.gemspec +15 -15
  87. metadata +164 -103
  88. data/Gemfile +0 -8
  89. data/lib/generators/wcc/templates/menu/generated_add_menus.ts +0 -192
  90. data/lib/generators/wcc/templates/page/generated_add_pages.ts +0 -50
  91. data/lib/tasks/validate.rake +0 -20
  92. data/lib/wcc/contentful/app/model_validators.rb +0 -121
  93. data/lib/wcc/contentful/app/model_validators/dsl.rb +0 -166
  94. data/lib/wcc/contentful/ext/model.rb +0 -5
@@ -0,0 +1,38 @@
1
+ <div class="row">
2
+ <div class="col">
3
+ <% section.testimonials&.each do |testimonial|
4
+ next unless testimonial %>
5
+ <div class="section-testimonials__item">
6
+ <% if testimonial.photo %>
7
+ <div class="section-testimonials__item-sidebar"
8
+ style="background-image: url(<%= testimonial.photo.file.url %>);">
9
+ </div>
10
+ <% end %>
11
+ <div class="section-testimonials__item-card">
12
+ <% if testimonial.quote.present? %>
13
+ <div
14
+ class="section-testimonials__item-card-quote
15
+ safe-line-break"><%= safe_line_break(testimonial.quote) %></div>
16
+ <% end %>
17
+ <div class="section-testimonials__item-card-meta">
18
+ <% if testimonial.photo %>
19
+ <%= image_tag(testimonial.photo.file.url,
20
+ alt: testimonial.photo.description || testimonial.photo.title,
21
+ class: 'section-testimonials__item-card-meta-photo') %>
22
+ <% end %>
23
+
24
+ <h3 class="section-testimonials__item-card-meta-name">
25
+ <%= testimonial.name %>
26
+ </h3>
27
+ <% if testimonial.mini_bio %>
28
+ <div class="section-testimonials__item-card-meta-bio">
29
+ <%= markdown(testimonial.mini_bio) %>
30
+ </div>
31
+ <% end %>
32
+ </div>
33
+ </div>
34
+ </div><!--quotation-->
35
+
36
+ <% end %>
37
+ </div><!--column-->
38
+ </div><!--row-->
@@ -0,0 +1,12 @@
1
+ <div class="row justify-content-center">
2
+ <div class="col col-lg-10">
3
+ <div class="section-video-content">
4
+ <% if section.title.present? %>
5
+ <h2 class="section-video-content__title"><%= section.title %></h2>
6
+ <% end %>
7
+ <div class="section-video-content__video embed-responsive embed-responsive-16by9">
8
+ <%= raw section.embed_code %>
9
+ </div>
10
+ </div>
11
+ </div>
12
+ </div>
@@ -0,0 +1,18 @@
1
+ <div class="row justify-content-center">
2
+ <div class="section-video-highlight__info col-xs-12 col-md-6">
3
+ <% if section.tag.present? %>
4
+ <span class="section-video-highlight__tag"><%= section.tag %></span>
5
+ <% end %>
6
+ <h2 class="section-video-highlight__title"><%= section.title %></h2>
7
+ <% if section.subtext.present? %>
8
+ <div class="section-video-highlight__subtext">
9
+ <%= markdown(section.subtext) %>
10
+ </div>
11
+ <% end %>
12
+ </div>
13
+ <div class="section-video-highlight__video col-xs-12 col-md-6">
14
+ <div class="embed-responsive embed-responsive-16by9">
15
+ <%= raw section.embed_code %>
16
+ </div>
17
+ </div>
18
+ </div><!--row-->
@@ -0,0 +1,7 @@
1
+
2
+ <h1>Contact Us Form Submission</h1>
3
+ <% @form_data.each do |key, value| %>
4
+ <p>
5
+ <%= key %> -> <%= value %>
6
+ </p>
7
+ <% end %>
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ # This command will automatically be run when you run "rails" with Rails gems
3
+ # installed from the root of your application.
4
+
5
+ ENGINE_ROOT = File.expand_path('..', __dir__)
6
+ ENGINE_PATH = File.expand_path('../lib/wcc/contentful/app/engine', __dir__)
7
+ APP_PATH = File.expand_path('../spec/dummy/config/application', __dir__)
8
+
9
+ # Set up gems listed in the Gemfile.
10
+ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
11
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
12
+
13
+ require 'rails/all'
14
+ require 'rails/engine/commands'
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ WCC::Contentful::App::Engine.routes.draw do
4
+ get '/*slug', to: 'wcc/contentful/app/pages#show'
5
+ root 'wcc/contentful/app/pages#index'
6
+ post '/contact_form', to: 'wcc/contentful/app/contact_form#create', as: :contact_form
7
+ end
@@ -5,14 +5,19 @@ module Wcc
5
5
  source_root File.expand_path('templates', __dir__)
6
6
  argument :model, type: :string
7
7
 
8
- VALID_MODELS = %w[menu page].freeze
8
+ VALID_MODELS =
9
+ Dir.glob("#{__dir__}/templates/*")
10
+ .select { |f| File.directory? f }
11
+ .map { |f| File.basename f }
12
+ .sort
13
+ .freeze
9
14
 
10
15
  def initialize(*)
11
16
  super
12
17
 
13
18
  return if VALID_MODELS.include?(singular)
14
19
 
15
- raise ArgumentError, "Model must be #{VALID_MODELS.to_sentence}"
20
+ raise ArgumentError, "Model must be one of #{VALID_MODELS.to_sentence}"
16
21
  end
17
22
 
18
23
  def ensure_migration_tools_installed
@@ -21,8 +26,9 @@ module Wcc
21
26
  package = JSON.parse(File.read('package.json'))
22
27
  deps = package['dependencies']
23
28
 
24
- unless deps.try(:[], 'contentful-migration-cli').present?
25
- run 'npm install --save watermarkchurch/migration-cli ts-node typescript contentful-export'
29
+ unless deps.try(:[], '@watermarkchurch/contentful-migration').present?
30
+ run 'npm install --save @watermarkchurch/contentful-migration ts-node ' \
31
+ 'typescript contentful-export'
26
32
  end
27
33
  end
28
34
  end
@@ -64,9 +70,13 @@ module Wcc
64
70
  copy_file 'wcc_contentful.rb', 'config/initializers/wcc_contentful.rb'
65
71
  end
66
72
 
67
- def create_model_migration
68
- copy_file "#{singular}/generated_add_#{plural}.ts",
73
+ def create_model_migrations
74
+ copy_file "#{singular}/migrations/generated_add_#{plural}.ts",
69
75
  "db/migrate/#{timestamp}01_generated_add_#{plural}.ts"
76
+
77
+ Dir.glob("#{__dir__}/templates/#{singular}/migrations/*.rb").each do |f|
78
+ copy_file f, "db/migrate/#{timestamp}_#{File.basename(f)}"
79
+ end
70
80
  end
71
81
 
72
82
  def drop_model_overrides_in_app_models
@@ -0,0 +1,285 @@
1
+ import Migration from '@watermarkchurch/contentful-migration';
2
+
3
+ export = function(migration: Migration, { makeRequest, spaceId, accessToken }) {
4
+ var menu = migration.createContentType('menu', {
5
+ displayField: 'internalTitle',
6
+ name: 'Menu',
7
+ description:
8
+ 'A Menu contains a number of Menu Buttons or other Menus, which will be rendered as drop-downs.'
9
+ });
10
+
11
+ menu.createField('internalTitle', {
12
+ name: 'Internal Title (Contentful Only)',
13
+ type: 'Symbol',
14
+ localized: false,
15
+ required: true,
16
+ validations: [],
17
+ disabled: false,
18
+ omitted: true
19
+ });
20
+
21
+ menu.createField('name', {
22
+ name: 'Menu Name',
23
+ type: 'Symbol',
24
+ localized: false,
25
+ required: true,
26
+ validations: [],
27
+ disabled: false,
28
+ omitted: false
29
+ });
30
+
31
+ menu.createField('items', {
32
+ name: 'Items',
33
+ type: 'Array',
34
+ localized: false,
35
+ required: false,
36
+ validations: [],
37
+ disabled: false,
38
+ omitted: false,
39
+ items: {
40
+ type: 'Link',
41
+ validations: [
42
+ {
43
+ linkContentType: ['dropdownMenu', 'menuButton'],
44
+ message: 'The items must be either buttons or drop-down menus.'
45
+ }
46
+ ],
47
+ linkType: 'Entry'
48
+ }
49
+ });
50
+
51
+ menu.changeEditorInterface('name', 'singleLine');
52
+ menu.changeEditorInterface('items', 'entryLinksEditor');
53
+ menu.changeEditorInterface('internalTitle', 'singleLine');
54
+
55
+ var menubutton = migration.createContentType('menuButton', {
56
+ displayField: 'internalTitle',
57
+ name: 'Menu Button',
58
+ description:
59
+ 'A Menu Button is a clickable button that goes on a Menu. It has a link to a Page or a URL.'
60
+ });
61
+
62
+ menubutton.createField('internalTitle', {
63
+ name: 'Internal Title (Contentful Only)',
64
+ type: 'Symbol',
65
+ localized: false,
66
+ required: true,
67
+ validations: [],
68
+ disabled: false,
69
+ omitted: true
70
+ });
71
+
72
+ menubutton.createField('text', {
73
+ name: 'Text',
74
+ type: 'Symbol',
75
+ localized: false,
76
+ required: false,
77
+ validations: [
78
+ {
79
+ size: {
80
+ min: 1,
81
+ max: 60
82
+ },
83
+ message:
84
+ 'A Menu Button should have a very short text field - ideally a single word. Please limit the text to 60 characters.'
85
+ }
86
+ ],
87
+ disabled: false,
88
+ omitted: false
89
+ });
90
+
91
+ menubutton.createField('icon', {
92
+ name: 'Icon',
93
+ type: 'Link',
94
+ localized: false,
95
+ required: false,
96
+ validations: [
97
+ {
98
+ linkMimetypeGroup: ['image']
99
+ }
100
+ ],
101
+ disabled: false,
102
+ omitted: false,
103
+ linkType: 'Asset'
104
+ });
105
+
106
+ menubutton.createField('materialIcon', {
107
+ name: 'Material Icon',
108
+ type: 'Symbol',
109
+ localized: false,
110
+ required: false,
111
+ validations: [
112
+ {
113
+ regexp: {
114
+ pattern: '^\\w+$',
115
+ flags: null
116
+ },
117
+ message:
118
+ "The icon name must be one of the icons in Google's Material Design library: https://material.io/tools/icons/"
119
+ }
120
+ ],
121
+ disabled: false,
122
+ omitted: false
123
+ });
124
+
125
+ menubutton.createField('externalLink', {
126
+ name: 'External Link',
127
+ type: 'Symbol',
128
+ localized: false,
129
+ required: false,
130
+ validations: [
131
+ {
132
+ regexp: {
133
+ pattern:
134
+ '^([^\\s\\:]+):(\\/\\/)?(\\w+:{0,1}\\w*@)?(([^\\s\\/#]+\\.)+[^\\s\\/#]+)(:[0-9]+)?(\\/|(\\/|\\#)([\\w#!:.?+=&%@!\\-\\/]+))?$|^(\\/|(\\/|\\#)([\\w#!:.?+=&%@!\\-\\/]+))$'
135
+ },
136
+ message:
137
+ "The external link must be a URL like 'https://www.watermark.org/', a mailto url like 'mailto:info@watermark.org', or a relative URL like '#location-on-page'"
138
+ }
139
+ ],
140
+ disabled: false,
141
+ omitted: false
142
+ });
143
+
144
+ menubutton.createField('link', {
145
+ name: 'Page Link',
146
+ type: 'Link',
147
+ localized: false,
148
+ required: false,
149
+ validations: [
150
+ {
151
+ linkContentType: ['page'],
152
+ message: 'The Page Link must be a link to a Page which has a slug.'
153
+ }
154
+ ],
155
+ disabled: false,
156
+ omitted: false,
157
+ linkType: 'Entry'
158
+ });
159
+
160
+ menubutton.createField('sectionLink', {
161
+ name: 'Section Link',
162
+ type: 'Link',
163
+ localized: false,
164
+ required: false,
165
+ validations: [
166
+ {
167
+ linkContentType: [
168
+ 'section-conference-speakers',
169
+ 'section-email-signup',
170
+ 'section-event-schedule',
171
+ 'section-faq',
172
+ 'section-hero',
173
+ 'section-hotels',
174
+ 'section-pricing',
175
+ 'section-social-links',
176
+ 'section-video-about'
177
+ ]
178
+ }
179
+ ],
180
+ disabled: false,
181
+ omitted: false,
182
+ linkType: 'Entry'
183
+ });
184
+
185
+ menubutton.createField('style', {
186
+ name: 'Style',
187
+ type: 'Symbol',
188
+ localized: false,
189
+ required: false,
190
+ validations: [
191
+ {
192
+ in: ['default', 'white-border']
193
+ }
194
+ ],
195
+ disabled: false,
196
+ omitted: false
197
+ });
198
+
199
+ menubutton.changeEditorInterface('text', 'singleLine');
200
+ menubutton.changeEditorInterface('icon', 'assetLinkEditor');
201
+ menubutton.changeEditorInterface('externalLink', 'singleLine', {
202
+ helpText:
203
+ 'Provide a URL to something on another website, a `mailto:` link to an email address, or a deep link into an app.'
204
+ });
205
+ menubutton.changeEditorInterface('link', 'entryLinkEditor');
206
+ menubutton.changeEditorInterface('internalTitle', 'singleLine');
207
+ menubutton.changeEditorInterface('style', 'dropdown');
208
+ menubutton.changeEditorInterface('sectionLink', 'entryLinkEditor', {
209
+ helpText:
210
+ 'If provided, this will link the user to the specific section on a page. You must use this in combination with Page Link.'
211
+ });
212
+ menubutton.changeEditorInterface('materialIcon', 'singleLine', {
213
+ helpText:
214
+ 'As an alternative to the Media icon, you can select an icon from here: https://material.io/tools/icons/'
215
+ });
216
+
217
+ var dropdownmenu = migration.createContentType('dropdownMenu', {
218
+ displayField: 'internalTitle',
219
+ name: 'Dropdown Menu',
220
+ description:
221
+ 'A Dropdown Menu can be attached to a main menu to show additional menu items on click.'
222
+ });
223
+
224
+ dropdownmenu.createField('internalTitle', {
225
+ name: 'Internal Title (Contentful Only)',
226
+ type: 'Symbol',
227
+ localized: false,
228
+ required: true,
229
+ validations: [],
230
+ disabled: false,
231
+ omitted: true
232
+ });
233
+
234
+ dropdownmenu.createField('name', {
235
+ name: 'Menu Name',
236
+ type: 'Symbol',
237
+ localized: false,
238
+ required: false,
239
+ validations: [],
240
+ disabled: false,
241
+ omitted: false
242
+ });
243
+
244
+ dropdownmenu.createField('label', {
245
+ name: 'Menu Label',
246
+ type: 'Link',
247
+ localized: false,
248
+ required: false,
249
+ validations: [
250
+ {
251
+ linkContentType: ['menuButton']
252
+ }
253
+ ],
254
+ disabled: false,
255
+ omitted: false,
256
+ linkType: 'Entry'
257
+ });
258
+
259
+ dropdownmenu.createField('items', {
260
+ name: 'Items',
261
+ type: 'Array',
262
+ localized: false,
263
+ required: false,
264
+ validations: [],
265
+ disabled: false,
266
+ omitted: false,
267
+ items: {
268
+ type: 'Link',
269
+ validations: [
270
+ {
271
+ linkContentType: ['menuButton']
272
+ }
273
+ ],
274
+ linkType: 'Entry'
275
+ }
276
+ });
277
+
278
+ dropdownmenu.changeEditorInterface('name', 'singleLine', {
279
+ helpText:
280
+ "If you don't set a menu label, this is the text that will appear on the button that opens the dropdown menu. If you do set a menu label, that will control the text."
281
+ });
282
+ dropdownmenu.changeEditorInterface('label', 'entryLinkEditor');
283
+ dropdownmenu.changeEditorInterface('items', 'entryLinksEditor');
284
+ dropdownmenu.changeEditorInterface('internalTitle', 'singleLine');
285
+ };
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This model represents the 'dropdownMenu' content type in Contentful. Any linked
4
+ # entries of the 'dropdownMenu' content type will be resolved as instances of this class.
5
+ # It exposes #find, #find_by, and #find_all methods to query Contentful.
6
+ class DropdownMenu < WCC::Contentful::Model::DropdownMenu
7
+ # Override functionality or add utilities
8
+ #
9
+ # # Example: override equality
10
+ # def ===(other)
11
+ # ...
12
+ # end
13
+ #
14
+ # # Example: override "name" attribute to always be camelized.
15
+ # # `@name` is populated by the gem in the initializer.
16
+ # def name
17
+ # @name_camelized ||= @name.camelize(true)
18
+ # end
19
+ end